fix(iot): не рвать автореконнект при сбое подписки (🔴6)
OnConnectHandler вызывал c.Disconnect(100) при таймауте/ошибке подписки. В paho это ЯВНОЕ отключение — автореконнект после него не срабатывает, и bridge «глохнет» (соединения нет, подписки нет, /ready=true). Теперь: подписка ретраится 3 раза с паузой 2с; при сбое — ждём следующего реконнекта (OnConnectHandler снова вызовется). Disconnect не вызывается.
This commit is contained in:
@@ -19,6 +19,10 @@ import (
|
|||||||
// telemetryTopicFilter — все namespace, все устройства.
|
// telemetryTopicFilter — все namespace, все устройства.
|
||||||
const telemetryTopicFilter = "+/telemetry/+"
|
const telemetryTopicFilter = "+/telemetry/+"
|
||||||
|
|
||||||
|
// subscribeRetryInterval — пауза между попытками подписки при сбое.
|
||||||
|
// Подписка обязательна (иначе bridge «глохнет»: соединение есть, а топик не слушается).
|
||||||
|
const subscribeRetryInterval = 2 * time.Second
|
||||||
|
|
||||||
// Run — бесконечный цикл bridge: подключение → подписка → ожидание сигнала завершения.
|
// Run — бесконечный цикл bridge: подключение → подписка → ожидание сигнала завершения.
|
||||||
func Run(ctx context.Context, cfg *config.Config, sqsClient *sqs.Client, log *slog.Logger) error {
|
func Run(ctx context.Context, cfg *config.Config, sqsClient *sqs.Client, log *slog.Logger) error {
|
||||||
log.Info("bridge: starting", "broker", cfg.MQTTBrokerURL, "client_id", cfg.MQTTClientID)
|
log.Info("bridge: starting", "broker", cfg.MQTTBrokerURL, "client_id", cfg.MQTTClientID)
|
||||||
@@ -86,18 +90,24 @@ func connectMQTT(ctx context.Context, cfg *config.Config, log *slog.Logger, hand
|
|||||||
})
|
})
|
||||||
opts.SetOnConnectHandler(func(c mqtt.Client) {
|
opts.SetOnConnectHandler(func(c mqtt.Client) {
|
||||||
log.Info("bridge: MQTT connected")
|
log.Info("bridge: MQTT connected")
|
||||||
|
// Подписка обязательна. Ретраим ограниченно. НЕ вызываем c.Disconnect():
|
||||||
|
// в paho это ЯВНОЕ отключение, после которого автореконнект НЕ срабатывает
|
||||||
|
// — bridge оставался бы отключённым навсегда (ревью 2026-10-10, 🔴6).
|
||||||
|
// При сбое ждём следующего реконнекта (OnConnectHandler вызовется заново).
|
||||||
|
for attempt := 1; attempt <= 3; attempt++ {
|
||||||
token := c.Subscribe(telemetryTopicFilter, 1, handler)
|
token := c.Subscribe(telemetryTopicFilter, 1, handler)
|
||||||
if !token.WaitTimeout(10 * time.Second) {
|
if token.WaitTimeout(10*time.Second) && token.Error() == nil {
|
||||||
log.Error("bridge: resubscribe timeout", "filter", telemetryTopicFilter)
|
log.Info("bridge: subscribed", "filter", telemetryTopicFilter, "attempt", attempt)
|
||||||
c.Disconnect(100) // принудительный реконнект (подписка обязательна)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if token.Error() != nil {
|
log.Error("bridge: subscribe failed", "filter", telemetryTopicFilter, "attempt", attempt, "err", token.Error())
|
||||||
log.Error("bridge: resubscribe failed", "filter", telemetryTopicFilter, "err", token.Error())
|
select {
|
||||||
c.Disconnect(100) // принудительный реконнект (подписка обязательна)
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
|
case <-time.After(subscribeRetryInterval):
|
||||||
}
|
}
|
||||||
log.Info("bridge: subscribed", "filter", telemetryTopicFilter)
|
}
|
||||||
|
log.Error("bridge: subscribe failed after retries, will retry on next reconnect", "filter", telemetryTopicFilter)
|
||||||
})
|
})
|
||||||
|
|
||||||
client := mqtt.NewClient(opts)
|
client := mqtt.NewClient(opts)
|
||||||
|
|||||||
Reference in New Issue
Block a user