Reconnect: keep the wait across short sessions, name a timeout and a lost link, setServer()

The wait between attempts started at 1 s again when the broker accepted the
session, so a session that was closed right after it opened (two boards with
one client id) came back every 2 s without end. It now starts again only
after a session that lasted 60 s; across shorter ones it keeps doubling.
An attempt given up after 30 s prints "the broker did not answer within
30 s", and loss of Wi-Fi prints "Wi-Fi is down, waiting for it" once per loss.
setServer(host, port) before begin() names another broker; the host is not
copied. basicLight: static RAM 30,616 B (+16), flash 333,701 B (+264);
91 host tests (bridge logic 50).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
David 2026-09-28 20:24:51 +00:00
parent d3e7ee7f2a
commit 42af413a6e
6 changed files with 164 additions and 23 deletions

View file

@ -791,7 +791,7 @@ void test_wait_doubles_from_a_second_to_a_minute()
}
}
void test_open_session_starts_the_wait_over()
void test_session_that_lasted_a_minute_starts_the_wait_over()
{
AlexaReconnectBackoff backoff;
@ -801,12 +801,64 @@ void test_open_session_starts_the_wait_over()
}
TEST_ASSERT_EQUAL_UINT32(60000, backoff.wait());
backoff.reset();
backoff.sessionOpened(100000);
TEST_ASSERT_EQUAL_UINT32(60000, backoff.wait());
backoff.sessionEnded(160000);
TEST_ASSERT_EQUAL_UINT32(1000, backoff.wait());
backoff.attempt();
TEST_ASSERT_EQUAL_UINT32(2000, backoff.wait());
}
// A broker that accepts the session and closes it at once, as it does to one of two boards with the same client id
void test_wait_keeps_doubling_across_sessions_that_end_early()
{
AlexaReconnectBackoff backoff;
const uint32_t expected[] = {1000, 2000, 4000, 8000, 16000, 32000, 60000, 60000};
uint32_t now = 5000;
for (uint32_t wait : expected)
{
backoff.sessionEnded(now);
TEST_ASSERT_EQUAL_UINT32(wait, backoff.wait());
now += wait;
backoff.attempt();
now += 200; // until the broker has accepted the session
backoff.sessionOpened(now);
now += 59999;
}
}
void test_attempt_that_fails_after_a_long_session_does_not_start_the_wait_over()
{
AlexaReconnectBackoff backoff;
backoff.sessionOpened(1000);
backoff.sessionEnded(3600000);
TEST_ASSERT_EQUAL_UINT32(1000, backoff.wait());
// The broker is gone: every attempt ends without a session, however long it took
backoff.attempt();
backoff.sessionEnded(3700000);
TEST_ASSERT_EQUAL_UINT32(2000, backoff.wait());
backoff.attempt();
backoff.sessionEnded(3800000);
TEST_ASSERT_EQUAL_UINT32(4000, backoff.wait());
}
void test_length_of_a_session_is_counted_across_the_overflow_of_millis()
{
AlexaReconnectBackoff backoff;
backoff.attempt();
backoff.sessionOpened(0xFFFFFF00u); // 256 ms before millis() starts again at 0
backoff.sessionEnded(59743);
TEST_ASSERT_EQUAL_UINT32(2000, backoff.wait());
backoff.sessionOpened(0xFFFFFF00u);
backoff.sessionEnded(59744);
TEST_ASSERT_EQUAL_UINT32(1000, backoff.wait());
}
void test_attempt_is_due_when_the_wait_is_over()
{
AlexaReconnectBackoff backoff;
@ -928,7 +980,10 @@ int main(int, char **)
RUN_TEST(test_log_never_prints_the_root_topic);
RUN_TEST(test_wait_doubles_from_a_second_to_a_minute);
RUN_TEST(test_open_session_starts_the_wait_over);
RUN_TEST(test_session_that_lasted_a_minute_starts_the_wait_over);
RUN_TEST(test_wait_keeps_doubling_across_sessions_that_end_early);
RUN_TEST(test_attempt_that_fails_after_a_long_session_does_not_start_the_wait_over);
RUN_TEST(test_length_of_a_session_is_counted_across_the_overflow_of_millis);
RUN_TEST(test_attempt_is_due_when_the_wait_is_over);
RUN_TEST(test_wait_is_counted_across_the_overflow_of_millis);