Files
cross-py-builder/ctrl/workers.py
T
Brett Williams 18d8d2e398 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.
2026-08-30 23:37:31 -05:00

59 lines
1.7 KiB
Python

import ctrl.db as db
import ctrl.settings as settings
import requests
def parse_worker(spec):
"""'host:port' -> {'url': 'http://host:port', 'host': host, 'port': port}."""
host, _, port = spec.strip().rpartition(":")
if not host or not port.isdigit():
raise ValueError(f"Invalid worker spec: {spec!r} (expected host:port)")
return {"url": f"http://{host}:{port}", "host": host, "port": int(port)}
def configured_workers():
out = []
for w in db.list_workers():
out.append({
"url": f"http://{w['host']}:{w['port']}",
"host": w["host"],
"port": w["port"],
})
return out
def probe_worker(url, timeout=None):
"""Return a normalized worker status dict, or None if unreachable."""
timeout = timeout or settings.WORKER_STATUS_TIMEOUT
try:
resp = requests.get(f"{url}/status", timeout=timeout)
resp.raise_for_status()
info = resp.json()
except (requests.RequestException, ValueError):
return None
info["url"] = url
info["online"] = True
return info
def probe_all():
workers = []
for w in configured_workers():
status = probe_worker(w["url"])
if status:
workers.append(status)
else:
workers.append({"url": w["url"], "host": w["host"], "port": w["port"], "online": False})
return workers
def matches(job, worker):
if worker.get("status") != "ready":
return False
if job.get("os_req") and job["os_req"].lower() not in str(worker.get("os", "")).lower():
return False
if job.get("cpu_req") and job["cpu_req"].lower() not in str(worker.get("cpu", "")).lower():
return False
return True