Manage workers from the web UI, persisted in SQLite

Replace the CROSS_PY_WORKERS env list with a DB-backed worker store so agents
can be added/removed (and their online status verified) from the browser.
- db.py: add workers table + list_workers/add_worker/remove_worker.
- workers.py: configured_workers() reads the DB instead of settings.
- app.py: POST /api/workers (add, probes reachability) and
  DELETE /api/workers/<port>/<host>; startup log uses DB worker count.
- UI: Workers card with add form, per-worker live status + OS/CPU, remove.
- settings.py: drop CROSS_PY_WORKERS/_get_json_list; DB is single source.
- README/DESIGN updated to describe UI-managed workers.
This commit is contained in:
Brett Williams
2026-08-30 23:37:31 -05:00
parent 5967b606c7
commit 18d8d2e398
10 changed files with 187 additions and 41 deletions
-17
View File
@@ -1,4 +1,3 @@
import json
import os
@@ -9,19 +8,6 @@ def _get_bool(name, default=False):
return val.strip().lower() in ("1", "true", "yes", "on")
def _get_json_list(name, default=None):
raw = os.environ.get(name)
if not raw:
return list(default or [])
try:
value = json.loads(raw)
except json.JSONDecodeError:
raise ValueError(f"{name} must be a JSON array string")
if not isinstance(value, list):
raise ValueError(f"{name} must be a JSON array")
return value
def _get_int(name, default):
raw = os.environ.get(name)
if raw is None:
@@ -34,9 +20,6 @@ DB_PATH = os.environ.get("CROSS_PY_DB", os.path.join(DATA_DIR, "jobs.db"))
BUILDS_DIR = os.environ.get("CROSS_PY_BUILDS", os.path.join(DATA_DIR, "builds"))
PORT = _get_int("CROSS_PY_PORT", 8080)
# Static worker list: JSON array of "host:port" strings.
WORKERS = _get_json_list("CROSS_PY_WORKERS")
# One job at a time by default; raise to allow parallel dispatches to distinct workers.
MAX_CONCURRENT = _get_int("CROSS_PY_MAX_CONCURRENT", 1)