From a366160dc8f403adfa8759547fda70823aa601d2 Mon Sep 17 00:00:00 2001 From: J3vb <192430104+J3vb@users.noreply.github.com> Date: Sat, 15 Aug 2026 22:57:01 +0200 Subject: [PATCH] test(ws): bound the load test's unregister settle by overallTimeout, not 5s (#1379) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TestTheLoadTest failed on the post-merge main run's windows-latest -race leg (job 95067154071) with "timed out after 5s waiting for churned clients to fully unregister" — every worker had finished, the hub was still running, and the goleak dump that followed was only the anchor drainers the t.Fatal skipped stopping. The runner was simply slow: the ws package took 276s against 159s on the identical tree an hour earlier, db and service ran 13-24% slower too, and Unregister drains asynchronously behind the hub loop's remaining broadcast work. Bound the settle wait by the test's own overallTimeout (90s), the same "only a genuine hang takes this long" limit the workers use. waitFor returns as soon as ClientCount matches, so a healthy run pays nothing — locally under -race the whole test still finishes in ~9s. Co-authored-by: Claude Fable 5 --- Server/ws/load_soak_test.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Server/ws/load_soak_test.go b/Server/ws/load_soak_test.go index bb54a47f..a00b9585 100644 --- a/Server/ws/load_soak_test.go +++ b/Server/ws/load_soak_test.go @@ -261,8 +261,15 @@ func TestTheLoadTest(t *testing.T) { } // Only the anchors should remain registered — every churned client - // unregistered itself at the end of its own round. - waitFor(t, 5*time.Second, func() bool { return hub.ClientCount() == numAnchors }, + // unregistered itself at the end of its own round. Those Unregister calls + // are async: they queue behind whatever broadcast work the hub loop still + // holds, and how long that drain takes scales with the runner. A fixed 5s + // budget failed on a slow windows-latest -race runner (the whole package + // ran 74% slower than usual) while the workers themselves had finished + // fine — so bound the settle by the same "only a genuine hang takes this + // long" limit the workers use. waitFor returns the moment the count + // matches, so a healthy run pays nothing extra. + waitFor(t, overallTimeout, func() bool { return hub.ClientCount() == numAnchors }, "churned clients to fully unregister") if got := hub.ClientCount(); got != numAnchors { t.Errorf("ClientCount = %d after churn settled, want %d (anchors only)", got, numAnchors)