Skip to content

fix(client-runtime): a busy thread stream no longer runs out of retries - #230

Merged
tusharbhardwaj-bk merged 2 commits into
expbkmainfrom
t3code/perf-17-client-retry-budget
Sep 27, 2026
Merged

tusharbhardwaj-bk merged 2 commits into
expbkmainfrom
t3code/perf-17-client-retry-budget

Conversation

@tusharbhardwaj-bk

@tusharbhardwaj-bk tusharbhardwaj-bk commented Sep 27, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Thread and shell subscriptions retry "expected" failures in the same WebSocket session with a bounded policy (threadSubscriptionRetryDelay: 250 ms, 500 ms, 1 s, 2 s, 4 s, 8 s). The most common one is the server's The live event buffer is full, which a busy thread hits whenever the client falls behind. The fork's code in packages/client-runtime/src/rpc/client.ts meant to reset the budget whenever a value arrives, and it did write attempt: 0 to retryState. But every retry computed its next attempt from retryAttempt, the value the stream started with, so the reset was ignored.

Result: after the 7th failure in one session, even with values arriving in between, the subscription went dormant. A busy running thread then sat on "The live event buffer is full…" until the socket reconnected. With desktop keep-alive, running threads stay mounted, so they can stay stale for the whole session.

Found by the client-sync analysis subagent.

Fix

Inside the existing T3-CUSTOM(expbkt3) block, each subscription attempt records when it first delivered a value. On an expected failure, the budget resets to 0 only if the attempt stayed healthy for 10 s after that first value (RETRY_BUDGET_RESET_AFTER_MS, longer than the longest 8 s retry delay); otherwise the attempt keeps counting. Delays, the dormant flag and the next subscription are unchanged.

A review by a fresh-context subagent caught that resetting on every value, the first version of this PR, would let a stream that fails right after each value retry forever at 250 ms.

Evidence

  • New rpc/client.retryBudget.expbkt3.test.ts, with a policy that allows only 2 consecutive retries:
    • A stream that stays healthy for 11 s between failures keeps retrying. It fails on the original code, which goes dormant after the 3rd failure.
    • A stream that fails right after each value still stops after 3 subscriptions, so there is no fast retry loop.
  • Existing rpc/client.test.ts: all pass (15 together with the new tests). state/threads-sync.test.ts + shell-sync.test.ts: 34 pass.
  • vp run typecheck in packages/client-runtime is clean, and the fork-marker check passes.

Reaches users: browser users on the next bkmain deploy; desktop users with the next desktop build (the app bundles its web UI).

Model/harness: Claude Opus 5.5 via Claude Code in T3 Code.

🤖 Generated with Claude Code

The fork's bounded retry for expected subscription failures (for example the
server's "live event buffer is full") meant to reset its budget whenever a
value arrived, but each retry computed its attempt from the attempt the
stream was started with. After the policy's last delay (7 failures for
threads), the subscription went dormant for the rest of the WebSocket
session even if values arrived between the failures, leaving a busy thread
stale until reconnect.

Each failure now reads the attempt from the shared retry state, which a
delivered value resets to 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added size:S vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Sep 27, 2026
Review found that resetting on every delivered value let a stream that
fails right after each value retry forever at the shortest delay. The
budget now resets only when an attempt stayed healthy for 10 s (longer than
the longest retry delay) after its first value; tests cover both cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added size:M and removed size:S labels Sep 27, 2026
@tusharbhardwaj-bk
tusharbhardwaj-bk merged commit e151037 into expbkmain Sep 27, 2026
12 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants