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.
This commit is contained in:
1 parent
c0c823b6b0
commit
6ffadd6e72
1 file changed
+6
-5
@@ -2280,10 +2280,10 @@ void MQTTBridge::maintainSlotConnection(int index, unsigned long now_millis, uns
|
||||
(_radio && _radio->getLastRecvMillis() > 0) ? (_ms->getMillis() - _radio->getLastRecvMillis()) : 0);
|
||||
if (slot_uses_jwt) {
|
||||
prepareJwtReconnect(true, -1);
|
||||
slot.client->reconnect();
|
||||
} else {
|
||||
slot.client->reconnect();
|
||||
}
|
||||
// Via the helper: reconnect() is a no-op on a client the WiFi-drop path
|
||||
// stopped, which would probe forever without ever starting it.
|
||||
reconnectSlotClient(index);
|
||||
// If the connect callback fires and sets slot.connected = true,
|
||||
// it will clear circuit_breaker_tripped via the onConnect handler
|
||||
}
|
||||
@@ -2314,12 +2314,13 @@ void MQTTBridge::maintainSlotConnection(int index, unsigned long now_millis, uns
|
||||
_last_slot_reconnect_ms = now_millis;
|
||||
if (slot_uses_jwt) {
|
||||
prepareJwtReconnect(false, slot.reconnect_backoff);
|
||||
slot.client->reconnect();
|
||||
} else {
|
||||
// Non-JWT slots — lightweight reconnect on existing client.
|
||||
MQTT_DEBUG_PRINTLN("MQTT%d reconnect (non-JWT, backoff %d)", index + 1, slot.reconnect_backoff);
|
||||
slot.client->reconnect();
|
||||
}
|
||||
// Via the helper: reconnect() is a no-op on a client the WiFi-drop path
|
||||
// stopped, which would back off forever without ever starting it.
|
||||
reconnectSlotClient(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user