fix(iot): /ready отражает факт подписки MQTT (находка #3)
Было: main выставлял ready.SetBridge(true) ПЕРЕД bridge.Run, поэтому «соединён, но подписка не прошла» давал /ready=200 и молча терял телеметрию до реконнекта. Теперь bridge сам управляет флагом (колбэк onSubscribed): true только после успешного SUBSCRIBE, false при потере соединения/сбое подписки.
This commit is contained in:
@@ -23,8 +23,18 @@ const telemetryTopicFilter = "+/telemetry/+"
|
||||
// Подписка обязательна (иначе bridge «глохнет»: соединение есть, а топик не слушается).
|
||||
const subscribeRetryInterval = 2 * time.Second
|
||||
|
||||
// Run — бесконечный цикл bridge: подключение → подписка → ожидание сигнала завершения.
|
||||
func Run(ctx context.Context, cfg *config.Config, sqsClient *sqs.Client, log *slog.Logger) error {
|
||||
// setSubscribed — nil-safe вызов колбэка состояния подписки.
|
||||
func setSubscribed(fn func(bool), v bool) {
|
||||
if fn != nil {
|
||||
fn(v)
|
||||
}
|
||||
}
|
||||
|
||||
// Run — бесконечный цикл bridge. onSubscribed — колбэк состояния подписки
|
||||
// (true после успешного SUBSCRIBE, false при потере соединения/сбое подписки):
|
||||
// /ready должен отражать реальную подписку, а не факт запуска горутины
|
||||
// (находка #3: «соединён, но не подписан» молча терял телеметрию при /ready=200).
|
||||
func Run(ctx context.Context, cfg *config.Config, sqsClient *sqs.Client, log *slog.Logger, onSubscribed func(bool)) error {
|
||||
log.Info("bridge: starting", "broker", cfg.MQTTBrokerURL, "client_id", cfg.MQTTClientID)
|
||||
|
||||
// URL очереди получаем один раз при старте (как старый consumer).
|
||||
@@ -46,7 +56,7 @@ func Run(ctx context.Context, cfg *config.Config, sqsClient *sqs.Client, log *sl
|
||||
|
||||
handler := newMessageHandler(dispatcher, log)
|
||||
|
||||
client, err := connectMQTT(ctx, cfg, log, handler)
|
||||
client, err := connectMQTT(ctx, cfg, log, handler, onSubscribed)
|
||||
if err != nil {
|
||||
dispatcher.closeAndWait()
|
||||
return err
|
||||
@@ -70,7 +80,7 @@ func (e errBridge) Error() string { return string(e) }
|
||||
|
||||
// connectMQTT устанавливает подключение к EMQX с автореконнектом.
|
||||
// handler передаётся в OnConnectHandler: подписка повторяется при каждом подключении.
|
||||
func connectMQTT(ctx context.Context, cfg *config.Config, log *slog.Logger, handler mqtt.MessageHandler) (mqtt.Client, error) {
|
||||
func connectMQTT(ctx context.Context, cfg *config.Config, log *slog.Logger, handler mqtt.MessageHandler, onSubscribed func(bool)) (mqtt.Client, error) {
|
||||
opts := mqtt.NewClientOptions()
|
||||
opts.AddBroker(cfg.MQTTBrokerURL)
|
||||
opts.SetClientID(cfg.MQTTClientID)
|
||||
@@ -84,6 +94,7 @@ func connectMQTT(ctx context.Context, cfg *config.Config, log *slog.Logger, hand
|
||||
|
||||
opts.SetConnectionLostHandler(func(_ mqtt.Client, err error) {
|
||||
log.Warn("bridge: MQTT connection lost, reconnecting...", "err", err)
|
||||
setSubscribed(onSubscribed, false)
|
||||
})
|
||||
opts.SetReconnectingHandler(func(_ mqtt.Client, _ *mqtt.ClientOptions) {
|
||||
log.Info("bridge: MQTT reconnecting...")
|
||||
@@ -98,6 +109,7 @@ func connectMQTT(ctx context.Context, cfg *config.Config, log *slog.Logger, hand
|
||||
token := c.Subscribe(telemetryTopicFilter, 1, handler)
|
||||
if token.WaitTimeout(10*time.Second) && token.Error() == nil {
|
||||
log.Info("bridge: subscribed", "filter", telemetryTopicFilter, "attempt", attempt)
|
||||
setSubscribed(onSubscribed, true)
|
||||
return
|
||||
}
|
||||
log.Error("bridge: subscribe failed", "filter", telemetryTopicFilter, "attempt", attempt, "err", token.Error())
|
||||
@@ -107,6 +119,9 @@ func connectMQTT(ctx context.Context, cfg *config.Config, log *slog.Logger, hand
|
||||
case <-time.After(subscribeRetryInterval):
|
||||
}
|
||||
}
|
||||
// Подписка не удалась — bridge не готов (/ready=503) до следующего
|
||||
// реконнекта.
|
||||
setSubscribed(onSubscribed, false)
|
||||
log.Error("bridge: subscribe failed after retries, will retry on next reconnect", "filter", telemetryTopicFilter)
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user