Queue scheduling and controls (#52) #106

Merged
crowmaki merged 3 commits from issue-52-queue-scheduling into main 2026-10-08 23:56:03 +00:00
Owner

Closes #52. Part of #24.

What changed

Scheduling (studio-core/src/schedule.rs, pure, unit-tested)

  • Classes run images → drafts → finals, FIFO within a class.
  • Model affinity within a class. The key is the Take's diffusion model file, which names its quantization; LoRAs are ignored. Image jobs use the checkpoint their workflow ships with. The worker prefers the first job on the loaded model, but only if every job ahead of it can still be passed over: fewer than 3 passes, and less than 5 minutes since it was first passed over. Otherwise the class runs in order.
  • Run next puts a selection at the global front, in its current order. It is exempt from affinity, releases holds and bypasses Hold finals. There is no pre-emption.

Controls (studio-core/src/queue.rs, schema V24)

  • Pause/Resume. Per-job Hold/Release. A sticky Hold finals switch, saved on the Project.
  • Drag reorders within a class, or within the Run next group. A move across classes is refused.
  • Cancel works on queued and running jobs. A running job's prompt is stopped with POST /api/jobs/{id}/cancel. If that answers anything but 200, the app falls back to /api/interrupt with prompt_id plus a /api/queue delete, and sends both. The worker also looks for cancellation while the job runs. If it finds one, it stops the prompt itself and drops the output, which covers a cancel that happens before ComfyUI has the prompt.
  • Cancelling a Take that then has no Rendition deletes the Take. Its number is burned (never reused). ADR-0004 is amended to allow this.
  • A cancelled Tile generation keeps its pixel-less version, because versions are append-only (DB trigger and the #24 amendment). It shows as Cancelled, not Failed.
  • At most one pending or running final per Take, enforced by a partial unique index on rendition. No final can be queued yet (#54/#57).
  • Failed jobs stay pinned at the top of the Queue panel until you dismiss them or open the failed Take.

Status

  • Takes have Held and Finishing states. Finishing runs from ComfyUI reporting done until the outputs are stored.
  • Badges (Queued / Held / Rendering % / Finishing / Failed) show on Take tiles and on the Shot rows in Setups and on the Board timeline.
  • The status bar shows Paused, held counts and Finals held.

UI

  • The Queue panel groups waiting jobs as Run next, Images, Drafts and Finals, with drag handles and checkboxes for multi-select Run next.
  • Each job has a menu with Run next, Hold/Release and Cancel. The header has Pause/Resume and a Hold finals switch, and a paused queue shows a banner.

Notes for the reviewer

  • Pause is saved on the Project too. That fits #53's "always reopens paused", which will set it on open.
  • A final held only by Hold finals has no per-job Release. Run next frees it, or you turn the switch off.

Tests

  • schedule.rs unit tests: class order, FIFO, affinity, the skip limit and window, Run next, holds, pause.
  • tests/queue_scheduling.rs runs against the fake ComfyUI. It covers class order, affinity with the 3-pass limit, drag and Run next, pause, hold and release, the Hold finals switch staying on after reopen, cancelling queued and running Takes (with and without the jobs API), cancel before ComfyUI reports, failed jobs pinned until dismissed, and one pending final per Take.
  • The fake ComfyUI gains JobScript::Hang, /interrupt, /queue and a switchable /jobs/{id}/cancel.
  • src-tauri/tests/takes.rs covers the RPC wiring. Bun tests cover the badge and grouping helpers.
  • Results: cargo test --workspace --all-features, bun test src scripts and bun run check all pass.

Screenshots

Queue docked at the bottom: paused, a failed job pinned, Run next and Drafts groups:
Queue panel, bottom dock

Queue docked on the right, with a held job and one ticked for Run next. The Shot row badge shows "2 queued":
Queue panel, right dock

Take tiles with Failed / Queued / Held badges:
Take badges

Opening a failed Take shows why it failed and dismisses its pinned job:
Failed Take opened

Closes #52. Part of #24. ## What changed **Scheduling** (`studio-core/src/schedule.rs`, pure, unit-tested) - Classes run images → drafts → finals, FIFO within a class. - Model affinity within a class. The key is the Take's diffusion model file, which names its quantization; LoRAs are ignored. Image jobs use the checkpoint their workflow ships with. The worker prefers the first job on the loaded model, but only if every job ahead of it can still be passed over: fewer than 3 passes, and less than 5 minutes since it was first passed over. Otherwise the class runs in order. - Run next puts a selection at the global front, in its current order. It is exempt from affinity, releases holds and bypasses Hold finals. There is no pre-emption. **Controls** (`studio-core/src/queue.rs`, schema V24) - Pause/Resume. Per-job Hold/Release. A sticky Hold finals switch, saved on the Project. - Drag reorders within a class, or within the Run next group. A move across classes is refused. - Cancel works on queued and running jobs. A running job's prompt is stopped with `POST /api/jobs/{id}/cancel`. If that answers anything but 200, the app falls back to `/api/interrupt` with `prompt_id` plus a `/api/queue` delete, and sends both. The worker also looks for cancellation while the job runs. If it finds one, it stops the prompt itself and drops the output, which covers a cancel that happens before ComfyUI has the prompt. - Cancelling a Take that then has no Rendition deletes the Take. Its number is burned (never reused). ADR-0004 is amended to allow this. - A cancelled Tile generation keeps its pixel-less version, because versions are append-only (DB trigger and the #24 amendment). It shows as **Cancelled**, not Failed. - At most one pending or running final per Take, enforced by a partial unique index on `rendition`. No final can be queued yet (#54/#57). - Failed jobs stay pinned at the top of the Queue panel until you dismiss them or open the failed Take. **Status** - Takes have **Held** and **Finishing** states. Finishing runs from ComfyUI reporting done until the outputs are stored. - Badges (Queued / Held / Rendering % / Finishing / Failed) show on Take tiles and on the Shot rows in Setups and on the Board timeline. - The status bar shows Paused, held counts and Finals held. **UI** - The Queue panel groups waiting jobs as Run next, Images, Drafts and Finals, with drag handles and checkboxes for multi-select Run next. - Each job has a menu with Run next, Hold/Release and Cancel. The header has Pause/Resume and a Hold finals switch, and a paused queue shows a banner. ## Notes for the reviewer - Pause is saved on the Project too. That fits #53's "always reopens paused", which will set it on open. - A final held only by Hold finals has no per-job Release. Run next frees it, or you turn the switch off. ## Tests - `schedule.rs` unit tests: class order, FIFO, affinity, the skip limit and window, Run next, holds, pause. - `tests/queue_scheduling.rs` runs against the fake ComfyUI. It covers class order, affinity with the 3-pass limit, drag and Run next, pause, hold and release, the Hold finals switch staying on after reopen, cancelling queued and running Takes (with and without the jobs API), cancel before ComfyUI reports, failed jobs pinned until dismissed, and one pending final per Take. - The fake ComfyUI gains `JobScript::Hang`, `/interrupt`, `/queue` and a switchable `/jobs/{id}/cancel`. - `src-tauri/tests/takes.rs` covers the RPC wiring. Bun tests cover the badge and grouping helpers. - Results: `cargo test --workspace --all-features`, `bun test src scripts` and `bun run check` all pass. ## Screenshots Queue docked at the bottom: paused, a failed job pinned, Run next and Drafts groups: ![Queue panel, bottom dock](https://git.crowmaki.me/attachments/f534b93a-beb5-421c-9bb7-141218ffe252) Queue docked on the right, with a held job and one ticked for Run next. The Shot row badge shows "2 queued": ![Queue panel, right dock](https://git.crowmaki.me/attachments/828dac12-282e-4aae-9db5-a187824272ca) Take tiles with Failed / Queued / Held badges: ![Take badges](https://git.crowmaki.me/attachments/d0ec463b-dfc0-49f4-97c1-82de545f3e55) Opening a failed Take shows why it failed and dismisses its pinned job: ![Failed Take opened](https://git.crowmaki.me/attachments/c68124ee-d49d-412e-894d-b481c715c1f0)
Classes run images, drafts, then finals, FIFO within a class, with model
affinity and a skip limit. Run next, drag reordering, Pause, per-job Hold,
a sticky Hold finals switch, cancel of waiting and running jobs (jobs
cancel endpoint, else interrupt plus queue delete) and dismissing failed
jobs. Takes report Held and Finishing, and at most one final per Take is
pending.
The Queue panel groups waiting jobs as Run next and one group per class,
drags within a group, and offers Pause/Resume, Hold finals, Hold, Run next,
Cancel and Dismiss. Take tiles and Shot listings show Queued, Held,
Rendering %, Finishing or Failed; opening a failed Take dismisses its job.
The class runs in order when a job ahead of the loaded-model job can no
longer be passed over. Image jobs key affinity on their checkpoint. A
running job looks for a cancel between events too, and the cancel fallback
sends both interrupt and queue delete. A cancelled Tile generation reads as
Cancelled, not Failed. The core reports whether a job is on hold, so the
webview no longer re-derives it. ADR-0004 now allows hard-deleting a Take
cancelled before it has a Rendition.
crowmaki deleted branch issue-52-queue-scheduling 2026-10-08 23:56:03 +00:00
Sign in to join this conversation.
No description provided.