fix(mqtt): measure the setup-retry interval from the failure

last_reconnect_attempt starts at zero and teardownSlot() re-zeroes it, so the
retry gate in maintainSlotConnections() reduced to "uptime >=
SLOT_SETUP_RETRY_INTERVAL". Past 60 s of uptime a failed setup was therefore
retried on the next maintenance pass rather than 60 s later -- in the same task
iteration for a live reconfigure, since reconfigure processing runs before
maintenance in the loop.

setupSlot() now stamps last_reconnect_attempt on each failure that represents a
real attempt (client allocation, and both JWT token paths), so all three callers
get the interval measured from the failure. The bounds check and the !enabled
early return are not attempts and stay unstamped. The reconnect ladder reads
this field only for slots with initial_connect_done set, which a failed setup
never sets, so reconnect timing is unaffected.

The retry path's own pre-call stamp is kept as a backstop for any future
false-returning path that does not stamp itself.
This commit is contained in:
agessaman
2026-08-04 14:04:08 -07:00
parent 6be84eb4eb
commit 53bae5684e
+11
View File
@@ -1759,9 +1759,18 @@ bool MQTTBridge::setupSlot(int index) {
return false;
}
// Every failure below is a real attempt, so stamp it: the retry interval in
// maintainSlotConnections() measures from last_reconnect_attempt, which starts at 0
// and is re-zeroed by teardownSlot(). Left unstamped, the gate degenerates to
// "uptime >= SLOT_SETUP_RETRY_INTERVAL" and a failure past that point is retried on
// the very next maintenance pass — the same task iteration, for a live reconfigure.
// The reconnect ladder never reads this field for an unactivated slot (it is gated
// on initial_connect_done), so stamping here cannot perturb reconnect timing.
// First setup for this slot allocates its persistent client; later ones reuse it.
if (!ensureSlotClient(index)) {
MQTT_DEBUG_PRINTLN("MQTT%d: client allocation failed - will retry", index + 1);
slot.last_reconnect_attempt = millis();
return false;
}
@@ -1825,6 +1834,7 @@ bool MQTTBridge::setupSlot(int index) {
if (slot.preset->auth_type == MQTT_AUTH_JWT) {
if (!createSlotAuthToken(index) || !slot.auth_token || slot.auth_token[0] == '\0') {
MQTT_DEBUG_PRINTLN("MQTT%d: no usable JWT token - will retry", index + 1);
slot.last_reconnect_attempt = millis();
return false;
}
slot.client->setCredentials(_jwt_username, slot.auth_token);
@@ -1939,6 +1949,7 @@ bool MQTTBridge::setupSlot(int index) {
// JWT auth for custom slot — same rule as the preset JWT path above.
if (!createSlotAuthToken(index) || !slot.auth_token || slot.auth_token[0] == '\0') {
MQTT_DEBUG_PRINTLN("MQTT%d: no usable JWT token - will retry", index + 1);
slot.last_reconnect_attempt = millis();
return false;
}
slot.client->setCredentials(_jwt_username, slot.auth_token);