feat(kanban): worker visibility endpoints (workers/active, runs/{id}, inspect)#23761
Closed
Interstellar-code wants to merge 1 commit into
Closed
feat(kanban): worker visibility endpoints (workers/active, runs/{id}, inspect)#23761Interstellar-code wants to merge 1 commit into
Interstellar-code wants to merge 1 commit into
Conversation
… inspect)
Adds three read-only endpoints to the kanban dashboard plugin so the
SwitchUI workspace (and any other dashboard consumer) can track
workers across tasks without N+1 round-trips through /tasks/{task_id}.
- GET /workers/active
Single SQL JOIN of task_runs + tasks where ended_at IS NULL,
worker_pid IS NOT NULL, status='running'. Returns
{workers: [...], count, checked_at}.
- GET /runs/{run_id}
Direct lookup of any task_run row by id. Reuses existing
kanban_db.get_run() helper and _run_dict() serialiser. 404 when
not found. Mirrors GET /tasks/{task_id} 404 shape.
- GET /runs/{run_id}/inspect
Live PID stats via psutil.Process.as_dict() — cpu_percent,
memory_rss_bytes, memory_vms_bytes, num_threads, num_fds, status,
create_time, cmdline. Short-circuits with alive:false when run
has ended, has no worker_pid, the pid is gone, or psutil is
unavailable. AccessDenied surfaces as alive:true with error
rather than a 500.
11 new tests in tests/plugins/test_kanban_worker_runs.py cover the
empty-board case, running-task case, ended-run filtering,
missing-pid filtering, 404 paths, already-ended inspect, no-pid
inspect, dead-pid inspect, and live-pid inspect (psutil mocked).
All pass.
Companion termination endpoint (POST /runs/{run_id}/terminate) is
intentionally out of scope here — opening a separate issue first
since the RBAC and dispatcher-mediated soft-cancel design needs
maintainer input before code.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Author
|
Related: #23762 (companion design discussion for the |
Contributor
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds three read-only endpoints to the kanban dashboard plugin so the dashboard, the workspace UI, or any external consumer can track workers across tasks without N+1 round-trips through
/tasks/{task_id}.GET /workers/activeGET /runs/{run_id}task_runsrow by id (404 when missing)GET /runs/{run_id}/inspectWhy
Today the only way to enumerate active workers is to fetch the full board, filter for
status='running', thenGET /tasks/{id}for each — N+1 round-trips just to render an "active workers" pane. Likewise, arun_idshown in logs or events can only be resolved by knowing which task it belongs to; there's no direct fetch._run_dictandkanban_db.get_runalready exist; this PR just exposes them at the route level and adds the cross-task active-worker JOIN + psutil inspector.Endpoint details
GET /workers/activeSQL JOIN of
task_runs+taskswherer.ended_at IS NULL AND r.worker_pid IS NOT NULL AND t.status='running'. Returns:```json
{
"workers": [
{
"run_id": 42, "task_id": "t_b621", "task_title": "...",
"task_status": "running", "task_assignee": "neo",
"profile": "claude", "worker_pid": 88421,
"started_at": 1778425200, "claim_lock": "mac:88421",
"claim_expires": 1778428800, "last_heartbeat_at": 1778425230,
"max_runtime_seconds": 3600
}
],
"count": 1,
"checked_at": 1778425280
}
```
`GET /runs/{run_id}`
Mirrors `GET /tasks/{task_id}` 404 pattern. Returns `{run: _run_dict(r)}` or 404.
`GET /runs/{run_id}/inspect`
Short-circuits with `{alive: false, reason}` for: run already ended, no `worker_pid` recorded, psutil missing, or PID gone (`NoSuchProcess`). `AccessDenied` returns `{alive: true, pid, error: "access denied"}` rather than a 500. POSIX-only `num_fds` is omitted gracefully on Windows.
Tests
`tests/plugins/test_kanban_worker_runs.py` — 11 new tests:
All pass under `uv run --extra dev --extra web pytest tests/plugins/test_kanban_worker_runs.py`.
Out of scope
A public `POST /runs/{run_id}/terminate` endpoint (wrapping the existing internal `_terminate_reclaimed_worker`) is being proposed in a separate issue, since its RBAC + soft-cancel-vs-force design needs maintainer input before code. Read-only endpoints land here first.
Validation
🤖 Generated with Claude Code