Skip to content

refactor(jobs): lift watch_cmd WS per-type decoding into a dispatch table (BE-2839)#505

Merged
bigcat88 merged 2 commits into
mainfrom
matt/be-2839-watch-cmd-dispatch
Jul 10, 2026
Merged

refactor(jobs): lift watch_cmd WS per-type decoding into a dispatch table (BE-2839)#505
bigcat88 merged 2 commits into
mainfrom
matt/be-2839-watch-cmd-dispatch

Conversation

@mattmillerai

Copy link
Copy Markdown
Collaborator

ELI-5

comfy jobs watch listens to a live WebSocket and, for each message, does one
of ~5 things depending on the message type (executing / cached / progress /
executed / error). That decision lived as one big nested if/elif chain inside
an already-long function. This PR moves only that per-message decoding into
small, individually-testable handler functions looked up from a dispatch table
(_WATCH_HANDLERS), each operating on an explicit _WatchState. Nothing about
when or how we connect, time out, reconnect, or decide the job finished
changed — that state machine stays exactly where it was.

What changed

  • Added _WatchState (a @dataclass) holding the per-watch context
    (renderer, prompt_id, host, port) plus the mutable accumulators the
    loop and handlers share (completed_nodes, outputs, end_reason,
    end_details) and a terminal flag handlers set to ask the recv loop to
    break.
  • Extracted the five message-type branches into module-level pure handlers
    (_watch_executing, _watch_execution_cached, _watch_progress,
    _watch_executed, _watch_execution_error) and a _WATCH_HANDLERS
    type → handler table.
  • watch_cmd now dispatches via the table and breaks when state.terminal is
    set. The WS connect, while True recv loop, per-recv timeout / snapshot
    reconnect (missing_deadline, saw_any_event), cancellation handling, and
    the post-loop terminal-status/payload rendering are unchanged — they just
    read/write through state.

Why it's safe (behavior-preserving)

  • The two terminal events keep their exact semantics: executing with a null
    node and execution_error set the terminal reason and emit nothing
    before the loop breaks, identical to the original.
  • saw_any_event is still set for any prompt-matched message (including
    unrecognized types); unknown types are still silently skipped (dict lookup
    miss ⇒ no handler).
  • The timeout-reconnect and cancel branches write the same fields, now on
    state, and the post-loop final_status/payload logic reads the same
    values.

Tests

  • Added focused unit tests for every handler and the dispatch table
    (tests/comfy_cli/jobs/test_jobs.py) — the WS loop previously had no direct
    unit coverage, so extracting the pure decoders let me lock their behavior.
  • Full suite green: 2360 passed, 12 skipped. ruff check / ruff format --check clean. No existing test modified.

Scope / judgment calls

  • Ticket was a DOWNGRADE — deliberately narrow. I lifted only the pure
    per-type decoding (as instructed) and left the connect/loop/terminal-detection
    state machine in place.
  • _WatchState intentionally carries the immutable render context alongside the
    mutable accumulators so handler signatures stay a clean (state, data); a
    reviewer could prefer a separate context object — flagging as a judgment call.
  • Negative-claim falsification clause: N/A — this is a pure structural refactor;
    it adds no capability-denying / dead-end path.

…able (BE-2839)

Extract the 5-way if/elif on msg type in watch_cmd into module-level
per-type handlers dispatched via _WATCH_HANDLERS over an explicit
_WatchState. The connect/recv-loop/timeout-reconnect/cancel and
terminal-detection state machine stays in watch_cmd unchanged; handlers
share loop-local state (completed_nodes, outputs, end_reason, end_details)
through _WatchState and signal loop termination via state.terminal.

Behavior-preserving: adds focused unit tests for each handler and the
dispatch table; existing jobs/watch tests pass unchanged.
@mattmillerai mattmillerai added agent-coded PR authored by the agent-work loop cursor-review Request Cursor bot review labels Jul 10, 2026
@mattmillerai mattmillerai marked this pull request as ready for review July 10, 2026 04:57
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 39 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fe627cf5-09b4-46be-a58f-f4a63b535ba8

📥 Commits

Reviewing files that changed from the base of the PR and between 91fbfd9 and 56a8cf2.

📒 Files selected for processing (2)
  • comfy_cli/command/jobs.py
  • tests/comfy_cli/jobs/test_jobs.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch matt/be-2839-watch-cmd-dispatch
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch matt/be-2839-watch-cmd-dispatch

Comment @coderabbitai help to get the list of available commands.

@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jul 10, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 Cursor Review — Consolidated panel

Triggered by @mattmillerai.

Found 3 finding(s).

Severity Count
🟡 Medium 1
🟢 Low 2

Panel: 6/8 reviewers contributed findings.

Reviewers that did not contribute: kimi-k2.5:adversarial (empty), kimi-k2.5:edge-case (empty)

Comment thread comfy_cli/command/jobs.py Outdated
Comment thread comfy_cli/command/jobs.py Outdated
Comment thread comfy_cli/command/jobs.py
Address review findings on the dispatch-table refactor:
- Guard the handler lookup with an isinstance(str) check: the dispatch
  table introduced a TypeError when a server sends an unhashable JSON
  array/object as the message ``type`` (dict.get on an unhashable key).
  The old if/elif chain tolerated this; unknown types now fall through
  and are ignored as before.
- Escape the server-controlled ``node`` id before printing it into the
  Rich markup string so it can't inject style/markup tags into pretty
  console output. The raw id is still carried on the event stream.

Add tests for the escape behavior.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Jul 10, 2026
@bigcat88 bigcat88 merged commit 2059d4c into main Jul 10, 2026
16 checks passed
@bigcat88 bigcat88 deleted the matt/be-2839-watch-cmd-dispatch branch July 10, 2026 11:19
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 10, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

agent-coded PR authored by the agent-work loop cursor-review Request Cursor bot review lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants