Repository navigation
The console shows each worker's load on its card and detail page #534
Description
Part of #527.
Scope
The console shows each worker's load in two places:
- A summary row on its card on the Workers page, which is also the Status panel at the top of its detail page.
- A Load panel with every figure and its age on its detail page.
This works on a gateway and on a single host alike, since both answer GET /v1/workers.
In short
The console already polls GET /v1/workers every second. It now renders the load block each view carries.
flowchart LR
A["GET /v1/workers: view.load"] --> M["load-model.ts (new)"]
M --> C["WorkerFacts: Load row (changed)"]
M --> D["worker detail: Load panel (new)"]
Card, before: Connection, Health, Protocol, Version, Devices, Capacity. After, a Load row right after Capacity, or right after Version on a starting worker, whose card leaves out Devices and Capacity:
| Worker | Load row |
|---|---|
| connected, every part read | CPU 34% · memory 9.8 of 32.0 GiB · disk 112.4 GiB free |
| limited CPU and memory | CPU 61% (limit) · memory 3.1 of 8.0 GiB (limit) · disk 40.2 GiB free |
| available memory under 1 GiB | memory 300 MiB of 8.0 GiB |
| CPU absent | CPU unavailable · memory 9.8 of 32.0 GiB · disk 112.4 GiB free |
| starting, sent load | as connected |
| connected, sent no load (an older worker) | Not reported, as for any other fact a worker did not send |
| disconnected | No reading while disconnected |
| incompatible | no row |
The detail page gets a Load panel, "How busy the machine is right now". It comes after the Host and Catalog row on a running worker. On a starting worker it comes after Host and before the "Devices, leases and capacity appear once startup finishes." line.
| Row | Example |
|---|---|
| CPU | 34% busy, 10 cores / 61% busy, 2 cores (limit) / 0.5 cores, 1 core, 0.01 cores |
| Memory | 9.8 GiB of 32.0 GiB available / 3.1 GiB of 8.0 GiB available (limit) |
| Swap | 1.2 GiB used |
| Pressure | normal (ok tone), warn (warn tone), critical (error tone) |
| Disk | 112.4 GiB of 494.4 GiB free |
| Read | 12 s ago, ticking every second, rounded up so a reading never looks fresher than it is |
The (limit) mark is plain muted text after the figure, like the for iOS note in the Host panel's tool list. It is not a status tone: a limited figure is not over its limit.
- An absent CPU, memory or disk shows
Unavailablein its row. - With memory absent, Swap and Pressure are left out, since both come from memory. Pressure is also left out whenever the view has none, as on Linux.
- A view with no
loadshowsNot reported.in the panel, orNo reading while disconnected.for a disconnected worker. - An incompatible worker's page has no Load panel.
If this goes wrong, an operator sees a missing, frozen or wrong load on a card or page.
Technical spec
Modules touched
flowchart LR
WF["views/worker-facts.tsx *"] --> LM["views/load-model.ts (new)"]
WD["views/worker-detail.tsx *"] --> LM
WD --> T["live/time.ts formatDuration"]
WD --> ST["status.tsx * (pressureStatus)"]
LM --> WM["views/workers-model.ts (WorkerView type)"]
ui/src/views/load-model.ts(new). Pure functions from aWorkerViewto the card summary and the detail rows. Formats match the CLI's Load line (A worker's simlock status shows its CPU, memory and disk load #531):- Bytes:
0 B, whole MiB below 1 GiB, GiB with one decimal from 1 GiB up, each rounded half up. A value that rounds to 1024 MiB is GiB. - Busy %: whole, rounded half up.
- Cores: up to one decimal, or two below 0.1, and
<0.01below 0.005,coresingular at exactly 1. - The card writes memory as
<available> of <total> GiBwhen both are GiB, and otherwise each with its own unit (300 MiB of 8.0 GiB).
- Bytes:
WorkerFactsgains the Load row, placed as the table above says. It is the same component on the card and in the detail page's Status panel, so the row shows in both. That is intended. The Status panel's description becomes "The worker's connection, health, capacity and load."worker-detail.tsxgains aLoadFactspanel, placed as above.- Its age uses the
nowpropWorkerDetailalready receives: the daemon's time, whichworkers.tsxfills fromuseNow().server. It does not calluseNow(). formatDurationrounds down, so the panel rounds the age up to a whole second first:formatDuration(Math.ceil((now - load.readAt) / 1000) * 1000).formatDurationalready shows a negative age as0 s.
- Its age uses the
ui/src/status.tsxgainspressureStatus, beside the other tone maps.- The existing test "says Not reported for a worker whose status never carried the block" in
worker-detail.test.tsxchecks the whole page for "Not reported.". The Load panel now prints that too, so the test is narrowed to the Warm pool panel's markup. Otherwise it would stay green with the warm pool broken.
Contract and event changes
None. The console reads the load block #533 adds to the worker view.
Other code on the same state
attention-model.tsreads the same views for the RAM budget item. It does not readload, and this task adds no attention item for load, because the feature has no thresholds.workers-model.tsworkersStatsandbusiestWorkersread the same views. They are unchanged.- feat(fleet): workers advertise their capabilities in status and worker list #519 (PR feat(fleet): workers advertise their capabilities in status and worker list #520) adds a Capabilities row to
WorkerFacts. It runs at the same time by the maintainer's choice, and the one that merges second places its row after the other's.
Rules in play
docs/internal/DESIGN.md: Status colours and Voice, for the new rows and words.testing.md.
Tests
The seams are load-model.ts directly, WorkerFacts and WorkerDetail through renderToStaticMarkup with a now prop, and the browser lane. Model them on these:
ui/src/views/workers-model.test.tsui/src/views/worker-detail.test.tsx("counts its devices and capacity, and says Not reported for what it has not read")e2e/console/workers.spec.ts("a worker's detail shows its host facts, catalog and installs in progress", and "a disconnected worker shows as disconnected within a second" for the fleet)
The test lines:
- the card summary lists CPU, memory and disk as the table in this issue shows, with
(limit)on a limited part, including memory under 1 GiB - the card summary says
CPU unavailable,memory unavailableordisk unavailablefor an absent part - bytes, busy % and cores format as the CLI's Load line does, including 0, 1023.6 MiB, 0.5 cores, 1 core and 0.001 cores (
<0.01 cores) - a running worker's card shows the Load row right after Capacity, and a starting worker's right after Version
- a worker card says
Not reportedfor a connected worker with no load, andNo reading while disconnectedfor a disconnected one - an incompatible worker's card and page have no Load row or panel
- a running worker's detail shows the Load panel after Host and Catalog, with CPU, memory, swap, pressure, disk and the reading's age
- a starting worker's detail shows the Load panel after Host and before the startup line
- a worker's detail leaves out Pressure when the view has none, and leaves out Swap and Pressure when memory is absent
- a worker's detail shows pressure
normal,warnandcriticalin the ok, warn and error tones - a worker's detail says
Unavailablein the row of an absent CPU, memory or disk - a worker's detail says
Not reported.in the Load panel with no load, andNo reading while disconnected.for a disconnected worker - a worker's detail ages the reading as
now − readAtrounded up to a whole second (4.1 s shows5 s ago), and shows a larger age for a laternow - the Status panel's description reads "The worker's connection, health, capacity and load.", and the Load panel's "How busy the machine is right now"
- a worker's detail writes
(limit)as muted text after a limited CPU or memory figure - the warm pool's Not reported test checks the Warm pool panel alone
- in a browser, a single host's card shows its Load row, and its detail shows the Load panel with an
s agoage that changes when read again a few seconds later, as the device time-in-state test does (about :346) - in a browser, with a gateway and two workers, stopping one turns its card's Load row into
No reading while disconnectedwithin a second of the gateway marking it disconnected
Done when
- Every test above is green.
- On a single host, the Workers page card shows the Load row, and the worker's page shows the Load panel with an age that ticks.
Out of scope
- Charts or history.
- An attention item for high load.
- Sorting or filtering workers by load.
Depends on
Approval
- Approved for delivery
Written by an agent.
Generated by Claude Code
Activity
test(ui): the console shows each worker's load on its card and detail…
feat(ui): the console shows each worker's load on its card and detail…
docs(console): the Workers page's Load row and Load panel (#534)
test(ui): single-host Load spec asserts memory, since CPU needs a sec…
fix(ui): the Load row follows Capabilities, as the spec orders it (#534)
test(ui): the console shows each worker's load on its card and detail…
feat(ui): the console shows each worker's load on its card and detail…
docs(console): the Workers page's Load row and Load panel (#534)
test(ui): single-host Load spec asserts memory, since CPU needs a sec…
fix(ui): the Load row follows Capabilities, as the spec orders it (#534)
test(ui): the console shows each worker's load on its card and detail…
3 remaining items
fix(ui): the Load row follows Capabilities, as the spec orders it (#534)
test(ui): the console shows each worker's load on its card and detail…
feat(ui): the console shows each worker's load on its card and detail…
docs(console): the Workers page's Load row and Load panel (#534)
test(ui): single-host Load spec asserts memory, since CPU needs a sec…
fix(ui): the Load row follows Capabilities, as the spec orders it (#534)
test(ui): wait twice as long for a worker's first Load reading (#534)
test(ui): the console shows each worker's load on its card and detail…
feat(ui): the console shows each worker's load on its card and detail…
docs(console): the Workers page's Load row and Load panel (#534)
test(ui): single-host Load spec asserts memory, since CPU needs a sec…
fix(ui): the Load row follows Capabilities, as the spec orders it (#534)
test(ui): wait twice as long for a worker's first Load reading (#534)
feat(ui): the console shows each worker's load on its card and detail…