Skip to content

Commit 6ffadd6

Browse files
committed
fix(mqtt): route both reconnect ladders through the stopped-client guard
reconnectSlotClient() checks isStarted() and calls connect() instead of reconnect() when the client was stopped, but only the post-NTP stale-token path used it. The ordinary backoff ladder and the circuit-breaker probe called slot.client->reconnect() directly, and esp_mqtt_client_reconnect() is a no-op on a client that is not started. Two ways in. connect() sets _started only when esp_mqtt_client_start() returns ESP_OK while setupSlot() sets initial_connect_done unconditionally, so a start failure under heap pressure stranded the slot. More routinely, the WiFi-drop handler calls disconnect() on every connected slot, which clears _started — after that the ladder issued no-ops forever and the slot never came back. Not caught by the soaks: the log line the guard prints can only come from the NTP path, so a stranded slot and a slot that never entered the state produce identical logs. Observed reconnects were broker-side drops with WiFi up, which leave the client started. The renewal-bounce path keeps its own isStarted() branch — it needs softDisconnect(), which the helper does not do.
1 parent c0c823b commit 6ffadd6

1 file changed

Lines changed: 6 additions & 5 deletions

File tree

src/helpers/bridges/MQTTBridge.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2280,10 +2280,10 @@ void MQTTBridge::maintainSlotConnection(int index, unsigned long now_millis, uns
22802280
(_radio && _radio->getLastRecvMillis() > 0) ? (_ms->getMillis() - _radio->getLastRecvMillis()) : 0);
22812281
if (slot_uses_jwt) {
22822282
prepareJwtReconnect(true, -1);
2283-
slot.client->reconnect();
2284-
} else {
2285-
slot.client->reconnect();
22862283
}
2284+
// Via the helper: reconnect() is a no-op on a client the WiFi-drop path
2285+
// stopped, which would probe forever without ever starting it.
2286+
reconnectSlotClient(index);
22872287
// If the connect callback fires and sets slot.connected = true,
22882288
// it will clear circuit_breaker_tripped via the onConnect handler
22892289
}
@@ -2314,12 +2314,13 @@ void MQTTBridge::maintainSlotConnection(int index, unsigned long now_millis, uns
23142314
_last_slot_reconnect_ms = now_millis;
23152315
if (slot_uses_jwt) {
23162316
prepareJwtReconnect(false, slot.reconnect_backoff);
2317-
slot.client->reconnect();
23182317
} else {
23192318
// Non-JWT slots — lightweight reconnect on existing client.
23202319
MQTT_DEBUG_PRINTLN("MQTT%d reconnect (non-JWT, backoff %d)", index + 1, slot.reconnect_backoff);
2321-
slot.client->reconnect();
23222320
}
2321+
// Via the helper: reconnect() is a no-op on a client the WiFi-drop path
2322+
// stopped, which would back off forever without ever starting it.
2323+
reconnectSlotClient(index);
23232324
}
23242325
}
23252326
}

0 commit comments

Comments
 (0)