Re-poll the update handle so long turns stop reporting failure - #211
Merged
Conversation
updateHandle.Get issues a long poll bounded by the SDK's own pollUpdateTimeout (60s in v1.46). When that window closes the gRPC call returns Canceled/DeadlineExceeded and the SDK surfaces WorkflowUpdateServiceTimeoutOrCanceledError WITHOUT retrying, even though the caller's context is still live. That error is about the client call, not the update -- the SDK documents it as "not related to any general concept of timing out or cancelling a running update". The workflow keeps running and the result still arrives; only the poll gave up. So any turn longer than the poll window reports failure while the work quietly succeeds. Observed with a bridged claude-code-swe-agent run: the UI showed Timeout or cancellation waiting for update: stream terminated by RST_STREAM with error code: CANCEL while AgentRun reached Succeeded, BridgedAgentWorkflow reached Completed, and the agent had already pushed its work. Minutes-long runs are the norm for a coding agent, so this is the common case rather than an edge. awaitTurnResult re-polls on that error and is used by both the streaming and non-streaming paths. The loop is bounded by ctx: the SDK returns the same error when the caller hangs up, so ctx.Err() is what separates "the window closed" from "nobody is listening", and prevents spinning. /invoke is deliberately untouched -- it sets its own invokePollTimeout and reports "still running" by design. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
updateHandle.Get issues a long poll bounded by the SDK's own pollUpdateTimeout (60s in v1.46). When that window closes the gRPC call returns Canceled/DeadlineExceeded and the SDK surfaces WorkflowUpdateServiceTimeoutOrCanceledError WITHOUT retrying, even though the caller's context is still live.
That error is about the client call, not the update -- the SDK documents it as "not related to any general concept of timing out or cancelling a running update". The workflow keeps running and the result still arrives; only the poll gave up.
So any turn longer than the poll window reports failure while the work quietly succeeds. Observed with a bridged claude-code-swe-agent run: the UI showed
Timeout or cancellation waiting for update: stream terminated by
RST_STREAM with error code: CANCEL
while AgentRun reached Succeeded, BridgedAgentWorkflow reached Completed, and the agent had already pushed its work. Minutes-long runs are the norm for a coding agent, so this is the common case rather than an edge.
awaitTurnResult re-polls on that error and is used by both the streaming and non-streaming paths. The loop is bounded by ctx: the SDK returns the same error when the caller hangs up, so ctx.Err() is what separates "the window closed" from "nobody is listening", and prevents spinning.
/invoke is deliberately untouched -- it sets its own invokePollTimeout and reports "still running" by design.