From e29c3d96bcde7981df5b266a19b0cce0073309de Mon Sep 17 00:00:00 2001 From: agessaman Date: Tue, 24 Mar 2026 20:35:37 -0700 Subject: [PATCH] Refactor MQTTBridge connection handling for JWT authentication. Implement full teardown and setup for JWT slots to ensure fresh TLS state and credentials during reconnect attempts. Preserve circuit breaker and backoff states across teardown to enhance connection stability and reliability. --- src/helpers/bridges/MQTTBridge.cpp | 37 +++++++++++++++++++----------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/helpers/bridges/MQTTBridge.cpp b/src/helpers/bridges/MQTTBridge.cpp index eff72c6e..f4f7d23c 100644 --- a/src/helpers/bridges/MQTTBridge.cpp +++ b/src/helpers/bridges/MQTTBridge.cpp @@ -979,17 +979,19 @@ void MQTTBridge::maintainSlotConnection(int index, unsigned long now_millis, uns slot.last_reconnect_attempt = now_millis; reconnect_attempted = true; MQTT_DEBUG_PRINTLN("MQTT%d circuit breaker probe (attempting single reconnect after %lu ms)", index + 1, probe_elapsed); - // Refresh JWT token before reconnecting (it may have expired while tripped) if (slot.preset && slot.preset->auth_type == MQTT_AUTH_JWT) { - if (createSlotAuthToken(index)) { - MQTT_DEBUG_PRINTLN("MQTT%d token refreshed before circuit breaker probe", index + 1); - slot.client->setCredentials(_jwt_username, slot.auth_token); - } + // JWT slots: full teardown+setup for fresh TLS state and credentials + // Preserve circuit breaker state across teardown + bool saved_tripped = slot.circuit_breaker_tripped; + teardownSlot(index); + setupSlot(index); + _slots[index].circuit_breaker_tripped = saved_tripped; + _slots[index].last_reconnect_attempt = now_millis; + } else { + slot.client->connect(); } - slot.client->connect(); // If the connect callback fires and sets slot.connected = true, - // the next maintenance cycle will clear the circuit breaker via the - // existing slot.reconnect_backoff = 0 / circuit_breaker reset logic + // it will clear circuit_breaker_tripped via the onConnect handler } } @@ -1017,14 +1019,21 @@ void MQTTBridge::maintainSlotConnection(int index, unsigned long now_millis, uns } MQTT_DEBUG_PRINTLN("MQTT%d reconnecting (backoff level %d, failures at max: %d)", index + 1, slot.reconnect_backoff, slot.max_backoff_failures); reconnect_attempted = true; - // Refresh JWT token before reconnecting (it may have expired during backoff) if (slot.preset && slot.preset->auth_type == MQTT_AUTH_JWT) { - if (createSlotAuthToken(index)) { - MQTT_DEBUG_PRINTLN("MQTT%d token refreshed before reconnect", index + 1); - slot.client->setCredentials(_jwt_username, slot.auth_token); - } + // JWT slots: full teardown+setup for fresh TLS state and credentials + // Preserve backoff state across teardown (which resets it to 0) + uint8_t saved_backoff = slot.reconnect_backoff; + uint8_t saved_failures = slot.max_backoff_failures; + MQTT_DEBUG_PRINTLN("MQTT%d teardown+setup for clean JWT reconnect", index + 1); + teardownSlot(index); + setupSlot(index); + _slots[index].reconnect_backoff = saved_backoff; + _slots[index].max_backoff_failures = saved_failures; + _slots[index].last_reconnect_attempt = now_millis; + } else { + // Non-JWT slots: lightweight reconnect on existing client + slot.client->connect(); } - slot.client->connect(); } } }