Skip to content

test(thread): stop real backoff wakeups racing the drainer test passes - #3379

Merged
stamp-build[bot] merged 1 commit into
mainfrom
agent/codex-android-devops/flaky-drainer-timeout
Oct 21, 2026
Merged

stamp-build[bot] merged 1 commit into
mainfrom
agent/codex-android-devops/flaky-drainer-timeout

Conversation

@stamp-build

@stamp-build stamp-build Bot commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

林舟 (Codex-Android-DevOPS) from slock-android opened this pull request through Stamp
View in Stamp →


Summary

Fixes the flaky ThreadPendingSendDrainerTest.timeoutExceptionIsClassifiedAndBackedOff (task #2 in #wg-mobile). It failed once in #3373's first CI run (expected [random-1, random-1]), and a rerun passed.

Cause (test only): these tests drive drain passes by hand with drainOnceForTests. When a test didn't pass a wakeups capture list, the helper left the real backoff scheduler armed. After a retryable failure (timeout, 5xx), that real wakeup launched a second drain pass on Dispatchers.Default, and it raced the backoff pass the test runs itself. Both passes could send the row, so send.randomIds became [random-1, random-1, random-1].

Production is not affected. In production every pass, including backoff wakeups, goes through the serial consumer loop (trigger → consumeLoop), so two passes never run at once.

Change:

  • The test helper now always captures wakeups (wakeups defaults to a fresh list), so no unit test arms a real timer.
  • The timeout test asserts that it armed exactly one 0ms wakeup, like the 429 retry test.

Verification

  • Reproduced before the fix: running the timeout scenario in a 2000× loop locally hit the triple send.
  • After the fix: 2000/2000 iterations passed, and the whole ThreadPendingSendDrainerTest class passed (14 tests, :shared:testDebugUnitTest). The loop was temporary and is not committed.

🤖 Generated with Claude Code

Tests drive drain passes by hand with drainOnceForTests, but the helper
left the real wakeup scheduler armed when a test did not pass a capture
list. After a retryable failure (timeout, 5xx) the real wakeup launched a
second pass on Dispatchers.Default that raced the test's own backoff pass,
so the same row could be sent three times. This made
timeoutExceptionIsClassifiedAndBackedOff fail now and then in CI.

Always capture wakeups in the helper, and assert the timeout test arms one.
Production is not affected: there every pass goes through the serial
consumer loop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@stamp-build
stamp-build Bot merged commit 98b960c into main Oct 21, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants