Skip to content

fix(client): honour an already-cancelled context before sending - #30

Merged
juicycleff merged 1 commit into
mainfrom
fix/client-expired-context
Aug 26, 2026
Merged

fix(client): honour an already-cancelled context before sending#30
juicycleff merged 1 commit into
mainfrom
fix/client-expired-context

Conversation

@juicycleff

Copy link
Copy Markdown
Contributor

request marshalled the frame, registered the pending channel and wrote the whole thing to the server before it ever looked at ctx, so a caller whose deadline had already blown still enqueued the job. The select at the bottom cannot cover for that. By the time it runs the response may already be sitting in respCh, and when both cases of a select are ready Go picks between them uniformly at random, so an expired context loses roughly half the time.

That is what TestClient_ContextTimeout caught on ubuntu CI, where the read goroutine gets to deliver the response before the requesting goroutine reaches the select. It never reproduced on darwin: 400 runs under load came back clean, because locally the round trip is always slower than the few microseconds between writeFrame returning and the select. Forcing the response to land first, by sleeping in between, failed 27 times in 40. With the check in place that same forced ordering failed 0 in 40.

All nine client calls across job, workflow and subscription route through request, so they all pick this up.

request marshalled the frame, registered the pending channel and wrote
the whole thing to the server before it ever looked at ctx, so a caller
whose deadline had already blown still enqueued the job. The select at
the bottom cannot cover for that. By the time it runs the response may
already be sitting in respCh, and when both cases of a select are ready
Go picks between them uniformly at random, so an expired context loses
roughly half the time.

That is what TestClient_ContextTimeout caught on ubuntu CI, where the
read goroutine gets to deliver the response before the requesting
goroutine reaches the select. It never reproduced on darwin: 400 runs
under load came back clean, because locally the round trip is always
slower than the few microseconds between writeFrame returning and the
select. Forcing the response to land first, by sleeping in between,
failed 27 times in 40. With the check in place that same forced
ordering failed 0 in 40.

All nine client calls across job, workflow and subscription route
through request, so they all pick this up.
@juicycleff
juicycleff merged commit 79ea9be into main Aug 26, 2026
13 checks passed
@juicycleff
juicycleff deleted the fix/client-expired-context branch August 26, 2026 14:48
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.

1 participant