Skip to content

Drop the Action Cable workarounds the client now handles - #407

Merged
monorkin merged 3 commits into
mainfrom
worktree-actioncable-lifecycle
Sep 8, 2026
Merged

Drop the Action Cable workarounds the client now handles#407
monorkin merged 3 commits into
mainfrom
worktree-actioncable-lifecycle

Conversation

@monorkin

@monorkin monorkin commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Picks up the Action Cable client's new lifecycle API (basecamp/actioncable-go#6 and #7) and drops the code here that was working around its silence.

  • Dial no longer closes a client behind its own error. A Connect that gives up now stops the client itself. Dial bounds the opening with its own timeout rather than leaving a caller who passed no deadline inside the retry loop for good.
  • A dial's credentials are fetched once. The pre-flight authHeader call is gone: an error from building the upgrade request now comes back wrapped in the one Connect returns, so a token that can't be built is reported instead of retried out of sight.
  • Client.Err says whether the shared TUI connection stopped, and why. That replaces calling Connect a second time and reading ErrAlreadyConnected as a sign of life. It also fixes a real case the probe got wrong: a rejected subscription would report a non-ErrAlreadyConnected error and condemn a connection the other watches were still using.
  • Subscription.Err says why the messages dried up, in place of the atomic.Bool that OnRejected used to set, and hey watch now reports what actually ended it.
  • Unsubscribe takes no context, so the goodbye no longer needs one built to outlive the watch that just ended.

One thing that stays

The Screener's separate reconnect channel. Its relay closes the channel when the watch's context ends, while the subscription behind it stays registered until the deferred goodbye, so a late callback would still write to a closed channel and panic off a goroutine Bubble Tea can't recover. That was never about the dispatcher draining callbacks after a stop, which is what its comment claimed — the comment is corrected here.

Checks

make check and make race-test both pass. The new test for the live-client path was mutation-checked: it fails when subscribeTuiCable treats a rejection as terminal.

@monorkin
monorkin requested a review from a team as a code owner September 7, 2026 16:54
Copilot AI balanced review requested due to automatic review settings September 7, 2026 16:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The lifecycle migration matches the updated dependency contracts and includes focused regression coverage.

Pull request overview

Adopts Action Cable’s lifecycle APIs and removes local connection-state workarounds.

Changes:

  • Uses Client.Err, Subscription.Err, and context-free Unsubscribe.
  • Bounds initial cable connections and preserves underlying errors.
  • Adds regression coverage for rejected subscriptions on live shared clients.

[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

File summaries
File Description
internal/cmd/watch.go Reports subscription termination through Subscription.Err.
internal/cmd/watch_test.go Tests interruption, closure, and rejection outcomes.
internal/cmd/watch_calendar.go Updates subscription teardown API usage.
internal/cmd/tui_watch.go Uses native client lifecycle state and teardown.
internal/cmd/tui_watch_test.go Covers rejection without discarding a live client.
internal/cable/cable.go Bounds connection opening and relies on client cleanup.
internal/cable/cable_test.go Verifies credential and failed-dial behavior.
go.mod / go.sum Updates actioncable-go to the required revision.
Review details
  • Files reviewed: 8/9 changed files
  • Comments generated: 0
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

The client reports its own lifecycle since basecamp/actioncable-go#6 and
#7, so the code here that worked that out for itself can go.

- A Connect that gives up stops the client, so Dial no longer closes one
  behind its own error. Dial bounds the opening itself rather than
  leaving a caller who passed no deadline inside the retry loop.

- A dial's credentials are no longer fetched twice. The error from
  building the upgrade request comes back with the one Connect returns,
  so a token that can't be built is reported rather than retried out of
  sight.

- Client.Err says whether the shared TUI connection stopped and why, in
  place of calling Connect again and reading ErrAlreadyConnected as a
  sign of life. It also stops a rejected subscription from condemning a
  connection the other watches are still using.

- Subscription.Err says why the messages dried up, in place of the flag
  OnRejected used to set, and the watch now reports what it was.

- Unsubscribe takes no context, so the goodbye no longer needs one built
  to outlive the watch that just ended.

The Screener's separate reconnect channel stays. Its relay closes on the
watch's context while the subscription behind it is still registered, so
a late callback would still write to a closed channel — that never had
anything to do with the dispatcher draining after a stop, and the comment
said otherwise.
@monorkin
monorkin force-pushed the worktree-actioncable-lifecycle branch from 6bc1402 to 9ee9bae Compare September 8, 2026 05:00
@monorkin monorkin changed the title Let the cable client say what we were working out for ourselves Drop the Action Cable workarounds the client now handles Sep 8, 2026
The lifecycle API this branch depends on has a release now, so the
pseudo-version pointing at a commit can go.
@monorkin
monorkin merged commit 43f14bc into main Sep 8, 2026
33 checks passed
@monorkin
monorkin deleted the worktree-actioncable-lifecycle branch September 8, 2026 05:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants