Unlock the Blazor input immediately when Cancel is clicked - #508
Merged
Conversation
Clicking Cancel published the cancel request but left the message input disabled until the reply timeout elapsed (3 minutes from the original send), because: - IsProcessing was cleared only in SendMessage's finally, which requires UserProxyService.SendAsync to return. - SendAsync blocks on a TaskCompletionSource keyed by the send's correlation id. - CancelSessionHandler publishes "Cancelled." to the broadcast topic with a fresh correlation id, so it never resolves that TCS. - UserMessageHandler excludes OperationCanceledException from every catch, so a cancelled turn publishes no correlated final reply. Nothing ever completed the pending request. SendMessage now owns a CancellationTokenSource whose token is passed to SendAsync; CancelSession cancels it and releases the UI before publishing, so the input unlocks on click. The finally guards on ReferenceEquals so a stale turn cannot unlock or re-lock over a newer send, and OperationCanceledException is caught separately to avoid a spurious error bubble. Co-Authored-By: Claude Opus 5 (1M context) <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.
@
Problem
Clicking Cancel published the cancel request but left the message input disabled until the reply timeout elapsed — 3 minutes from the original send. The chain:
IsProcessingwas cleared only inSendMessagesfinally, which requiresUserProxyService.SendAsyncto return.SendAsyncblocks on aTaskCompletionSourcekeyed by the sends correlation id.CancelSessionHandlerpublishes"Cancelled."to the broadcast topic with a fresh correlation id, so it never resolves that TCS.UserMessageHandlerexcludesOperationCanceledExceptionfrom every catch, so a cancelled turn publishes no correlated final reply.Nothing ever completed the pending request.
Fix
SendMessagenow owns aCancellationTokenSourcewhose token is passed toSendAsync.CancelSessioncancels it and releases the UI before publishing, so the input unlocks on click.This works because
UserProxyService.SendAsynclinks the callers token into its timeout CTS, and its catch filterwhen (!cancellationToken.IsCancellationRequested)deliberately lets external cancellation propagate rather than swallowing it as a timeout. The newcatch (OperationCanceledException)inChat.razorabsorbs that, avoiding a spurious error bubble — the agent publishes its own"Cancelled."bubble. The pending entry is still removed inSendAsyncsfinally, so there is no leak.The
finallyguards onReferenceEqualsso a stale turn cannot unlock or re-lock over a newer send.Testing
Built and deployed to the live cluster as
rockylhotka/rockbot-blazor:0.14.11-cancelfixfor manual verification. Clean startup: RabbitMQ connected, both response topics subscribed. Scope is a single.razorfile with no test coverage in this project; verification is manual — cancel unlocks the input immediately, and a cancel-then-immediately-send sequence does not let the stale turn re-lock the input.🤖 Generated with Claude Code
@