Skip to content

Unlock the Blazor input immediately when Cancel is clicked - #508

Merged
rockfordlhotka merged 1 commit into
mainfrom
fix/blazor-cancel-unlocks-input
Aug 11, 2026
Merged

Unlock the Blazor input immediately when Cancel is clicked#508
rockfordlhotka merged 1 commit into
mainfrom
fix/blazor-cancel-unlocks-input

Conversation

@rockfordlhotka

Copy link
Copy Markdown
Member

@

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:

  • IsProcessing was cleared only in SendMessages finally, which requires UserProxyService.SendAsync to return.
  • SendAsync blocks on a TaskCompletionSource keyed by the sends 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.

Fix

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.

This works because UserProxyService.SendAsync links the callers token into its timeout CTS, and its catch filter when (!cancellationToken.IsCancellationRequested) deliberately lets external cancellation propagate rather than swallowing it as a timeout. The new catch (OperationCanceledException) in Chat.razor absorbs that, avoiding a spurious error bubble — the agent publishes its own "Cancelled." bubble. The pending entry is still removed in SendAsyncs finally, so there is no leak.

The finally guards on ReferenceEquals so 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-cancelfix for manual verification. Clean startup: RabbitMQ connected, both response topics subscribed. Scope is a single .razor file 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
@

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>
@rockfordlhotka
rockfordlhotka merged commit 64cb1ed into main Aug 11, 2026
2 checks passed
@rockfordlhotka
rockfordlhotka deleted the fix/blazor-cancel-unlocks-input branch August 11, 2026 17:17
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