MQTT will delay interval, broker'a bir istemcinin Last Will mesajını publish etmeden önce belirli bir saniye beklemesini ve istemci zamanında yeniden bağlanırsa mesajı tamamen iptal etmesini söyleyen bir MQTT 5 özelliğidir. Bu yazıda kısa ağ kesintilerinin neden olduğu gürültülü çevrimdışı uyarılarını nasıl bastırdığını, session expiry ile nasıl etkileştiğini ve mosquitto, Python ve Node.js'te nasıl yapılandırılacağını göreceksiniz.
Sorun: Sürekli Yanıp Sönen Çevrimdışı Uyarıları
Last Will and Testament, MQTT'nin bir istemcinin ortadan kaybolduğunu duyurmak için sunduğu yerleşik yöntemdir. İstemci, bağlanırken bir will mesajı kaydeder (genellikle bir durum topic'inde retained bir offline) ve bağlantı düzgün bir DISCONNECT olmadan sona ererse broker bu mesajı publish eder.
MQTT 3.1.1'de will, broker arızayı tespit eder etmez publish edilir. Gerçek ağlarda bu gürültülüdür:
- Bir Wi-Fi erişim noktası cihazı başka bir AP'ye aktarır ve TCP bağlantısı sıfırlanır.
- Bir hücresel modem yeniden müzakere yapar ve cihaz saniyeler içinde geri döner.
- Bir gateway, yapılandırma değişikliğinden sonra MQTT sürecini yeniden başlatır.
Her durum, birkaç an sonra online ile takip edilen bir offline mesajı üretir. Dashboard'lar yanıp söner, alarm kuralları tetiklenir ve operatörler uyarıları görmezden gelmeyi öğrenir; bu da hiç uyarı olmamasından daha kötüdür.
MQTT Will Delay Interval Nasıl Çalışır?
MQTT 5, CONNECT içindeki will mesajına eklenen, saniye cinsinden dört baytlık bir özellik olan Will Delay Interval'ı getirir. Ağ bağlantısı anormal şekilde kapandığında:
- Broker, will delay interval süresi için bir zamanlayıcı başlatır.
- Aynı istemci zamanlayıcı dolmadan aynı oturuma yeniden bağlanırsa will publish edilmez.
- Önce zamanlayıcı dolarsa will her zamanki gibi publish edilir.
- Önce oturum sona ererse (session expiry interval dolduğu için) will o anda publish edilir.
Varsayılan değer 0'dır ve 3.1.1'deki anında yayınlama davranışını yeniden üretir.
Herkesin Gözden Kaçırdığı Kural: Session Expiry
Will, gecikme süresi geçtiğinde veya oturum sona erdiğinde, hangisi önce gelirse publish edilir. İstemci 0 session expiry interval ile bağlanırsa oturum bağlantının kapandığı anda sona erer; dolayısıyla will hemen gönderilir ve gecikmenizin hiçbir etkisi olmaz.
| Will delay | Session expiry | Sonuç |
|---|---|---|
| 0 | herhangi | Anormal bağlantı kesilmesinde anında will |
| 30 sn | 0 | Anında will (önce oturum sona erdi) |
| 30 sn | 60 sn | İstemci yeniden bağlanmazsa 30 sn sonra will |
| 30 sn | 10 sn | 10 sn sonra will (önce oturum sona erdi) |
| 300 sn | 3600 sn | İstemci yeniden bağlanmazsa 5 dakika sonra will |
Bu nedenle will delay kullanmak için her zaman en az gecikme kadar uzun bir session expiry interval ayarlayın ve broker'ın yeni bağlantıyı aynı oturum olarak değerlendirmesi için Clean Start false olarak yeniden bağlanın. Ayrıntılar MQTT 5 clean start ve session expiry interval yazısında.
Keep Alive Toplam Süreye Eklenir
Zamanlayıcı ancak broker bağlantının gittiğini fark ettiğinde başlar. Bir cihazın gücü kesilirse tespit, keep alive süresinin 1,5 katına kadar sürer. 60 saniyelik keep alive ve 30 saniyelik will delay ile çevrimdışı mesajına kadar geçen en kötü durum süresi yaklaşık iki dakikadır. İkisini birlikte planlayın; bkz. MQTT keep alive süresini seçmek.
Will Delay Değerini Seçmek
Normal yeniden bağlanma sürenizi kapsayan en kısa gecikmeyi seçin.
- Hızlı yeniden bağlanma mantığına sahip Wi-Fi cihazları: 10 ila 30 saniye.
- Hücresel cihazlar: 30 ila 120 saniye; modemin yeniden kaydı daha yavaştır.
- Güncellemeler sırasında servislerini yeniden başlatan gateway'ler: tipik bir yeniden başlatmadan biraz daha uzun.
- Güvenlik açısından kritik ekipmanlar: kısa tutun veya 0 yapın. Gecikmiş bir alarm, yanlış bir alarmdan daha pahalıya mal olabilir.
Pratik bir test: gerçek çalışmanın bir haftası boyunca bağlantı kesilmesi ile yeniden bağlanma arasındaki süreyi loglayın ve bu aralıkların büyük kısmının hemen üzerinde bir değer seçin.
Will Delay'i Kodda Yapılandırmak
Tüm örnekler broker.connectmq.com adresindeki herkese açık MQTT test broker'ını kullanır. w3d8 değerini kendi rastgele dizenizle değiştirin ve herkese açık alanın herkes tarafından okunabildiğini unutmayın.
Simüle Edilmiş Cihaz Olarak mosquitto_sub
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 \
-i willdelay-dev-w3d8 -c -x 120 \
--will-topic 'connectmq/demo/w3d8/status' \
--will-payload 'offline' --will-qos 1 --will-retain \
-D will will-delay-interval 30 \
-t 'connectmq/demo/w3d8/cmd'
Başka bir terminalde durum topic'ini izleyin:
mosquitto_sub -h broker.connectmq.com -p 1883 -i willdelay-watch-w3d8 \
-v -t 'connectmq/demo/w3d8/status'
mosquitto_sub'da Ctrl+C düzgün bir DISCONNECT gönderir ve bu hiçbir zaman will tetiklemez. Gerçek bir arızayı simüle etmek için bunun yerine süreci sonlandırın (örneğin süreç kimliğine kill -9 uygulayarak veya ağ kablosunu çekerek). Ardından iki durumu deneyin: cihaz komutunu 30 saniye içinde yeniden başlatırsanız hiçbir offline görünmez; daha uzun beklerseniz görünür.
Python (paho-mqtt 2.x)
import paho.mqtt.client as mqtt
from paho.mqtt.properties import Properties
from paho.mqtt.packettypes import PacketTypes
STATUS = "connectmq/demo/w3d8/status"
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id="willdelay-py-w3d8",
protocol=mqtt.MQTTv5)
will_props = Properties(PacketTypes.WILLMESSAGE)
will_props.WillDelayInterval = 30 # saniye
client.will_set(STATUS, payload="offline", qos=1, retain=True,
properties=will_props)
def on_connect(client, userdata, flags, reason_code, properties):
print("Connected:", reason_code)
# Çevrimiçi olduğumuzu duyur (retained "offline" mesajının üzerine yazar)
client.publish(STATUS, "online", qos=1, retain=True)
client.on_connect = on_connect
connect_props = Properties(PacketTypes.CONNECT)
connect_props.SessionExpiryInterval = 120 # will delay'den büyük veya eşit olmalı
client.connect("broker.connectmq.com", 1883, keepalive=30,
clean_start=False, properties=connect_props)
client.loop_forever()
Node.js (MQTT.js v5)
const mqtt = require("mqtt");
const STATUS = "connectmq/demo/w3d8/status";
const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
clientId: "willdelay-node-w3d8",
protocolVersion: 5,
clean: false,
keepalive: 30,
properties: { sessionExpiryInterval: 120 },
will: {
topic: STATUS,
payload: Buffer.from("offline"),
qos: 1,
retain: true,
properties: { willDelayInterval: 30 },
},
});
client.on("connect", () => {
client.publish(STATUS, "online", { qos: 1, retain: true });
});
Eksiksiz Bir Çevrimiçi/Çevrimdışı Kalıbı
Will delay, tutarlı bir varlık (presence) tasarımının parçası olduğunda en iyi sonucu verir:
- Will delay ve buna uygun session expiry ile retained bir
offlinewill kaydedin. - Her başarılı bağlantının hemen ardından retained bir
onlinepublish edin. - Planlı bir kapatmadan önce retained
offlinemesajını kendiniz publish edin, ardından bağlantıyı düzgün şekilde kesin. - Dashboard'ların ve alarm kurallarının yalnızca retained durum topic'ini okumasını sağlayın.
- İsteğe bağlı olarak, operatörlerin bir cihazın neden çevrimdışı olduğunu görebilmesi için JSON payload'a bir zaman damgası veya neden ekleyin.
Diğer varlık kalıpları MQTT cihaz çevrimiçi durumu yazısında ele alınıyor. Bir ConnectMQ broker'ında, uygulama düzeyindeki durumunuz yerine broker'ın ham bağlantıya dair görünümünü yansıtan $SYS/broker/connection/{clientId}/state topic'iyle de çapraz kontrol yapabilirsiniz.
Will Delay ile Uygulamada Debounce Karşılaştırması
MQTT 5'ten önce ekipler, bu yanıp sönme sorununu tüketici tarafında debounce ile çözüyordu: bir dashboard veya uyarı servisi, bir offline mesajından sonra N saniye bekliyor ve ancak ardından online gelmezse alarm veriyordu. Bu yöntem hâlâ işe yarar, ancak her tüketicinin aynı mantığı uygulaması gerekir ve her biri farklı bir pencere seçebilir. Will delay kararı broker'a taşır; böylece her subscriber aynı, önceden filtrelenmiş durum akışını görür. Bunun bedeli, gecikmenin bağlantı anında istemci bazında ayarlanmasıdır; yani değeri değiştirmek tek bir backend servisi yerine cihaz yapılandırmasını güncellemek anlamına gelir.
Will Delay Sorunlarını Gidermek
- Will hâlâ hemen tetikleniyor: session expiry 0 veya will delay'den kısa ya da MQTT 3.1.1 ile bağlanıyorsunuz.
- Cihaz hızla yeniden bağlanmasına rağmen will tetikleniyor: cihaz Clean Start true ile veya farklı bir client ID ile yeniden bağlandı; dolayısıyla bu yeni bir oturumdu.
- Will hiç tetiklenmiyor: istemci bağlantıyı düzgün şekilde kesti veya gecikme beklediğinizden uzun. Keep alive tespit süresini de eklemeyi unutmayın.
- Yeniden bağlandıktan sonra eski
offlinegörünüyor: retainedonlinemesajını yalnızca ilk bağlantıda değil, her bağlantıda publish edin.
Bu kavramlarda yeni misiniz? MQTT eğitimi will'leri, oturumları ve retained mesajları en baştan açıklıyor.
ConnectMQ'da Güvenilir Cihaz Durumu Oluşturun
ConnectMQ; will özellikleri, session expiry ve retained mesajlar dahil tam MQTT 5.0 desteğine sahip yönetilen bir MQTT broker'dır. Portalı eşik tabanlı alarm kuralları ve bir alarm günlüğü de sunar; dolayısıyla protokol düzeyinde daha temiz durum verisi, bunun üzerine kurduğunuz kurallardan daha az gürültülü uyarı anlamına gelir. Kredi kartı gerektirmeden Serverless planında ücretsiz başlayın, YOUR_USERNAME, YOUR_PASSWORD ve YOUR_CLIENT_ID ile bağlanın ve will delay ayarlarınızı kendi broker'ınızda test edin.
Sık Sorulan Sorular
Varsayılan MQTT will delay interval nedir?
Varsayılan değer 0 saniyedir; yani will mesajı, tıpkı MQTT 3.1.1'de olduğu gibi broker anormal bir bağlantı kesilmesini tespit eder etmez publish edilir.
Will mesajım neden gecikmeyi yok sayıyor?
Çoğu zaman session expiry interval 0'dır veya will delay'den kısadır. Broker will'i oturum sona erdiğinde publish eder; bu nedenle oturumun en az gecikme kadar sürmesi gerekir.
Will delay MQTT 3.1.1'de mevcut mu?
Hayır. Bu bir MQTT 5 özelliğidir. MQTT 3.1.1'de bunun yerine çevrimdışı olaylarını tüketen uygulamada debounce yapmanız gerekir.
Düzgün bir bağlantı kesme will mesajını tetikler mi?
Hayır. Normal bir DISCONNECT will'i atar. MQTT 5'te bir istemci, 0x04 (Disconnect with Will Message) reason code'uyla bağlantıyı keserek will'i bilinçli olarak isteyebilir.



