Add controller logging and return readable errors

The controller ran silently and surfaced errors as opaque/empty bodies,
making it impossible to diagnose failures from either the UI or the server.
- Configure Python logging (timestamps, levels) and log job lifecycle events
  (created / dispatched / done / failed) plus startup and dispatch warnings.
- Add a catch-all error handler so unhandled exceptions return a JSON error
  with the exception type+message instead of an empty response.
- Remove the frontend submit bug that hand-set multipart Content-Type without
  a boundary (and built an opts object it never used); post the FormData
  directly so the browser sets the correct content type + boundary.
This commit is contained in:
Brett Williams
2026-08-30 22:39:16 -05:00
parent 6f38beaf92
commit 8a6f02b7e9
3 changed files with 31 additions and 2 deletions
+8
View File
@@ -1,4 +1,5 @@
import datetime
import logging
import os
import threading
import time
@@ -9,6 +10,8 @@ import ctrl.db as db
import ctrl.settings as settings
import ctrl.workers as wrk
log = logging.getLogger("ctrl.scheduler")
class Scheduler:
def __init__(self):
@@ -78,6 +81,7 @@ class Scheduler:
job_id = job["id"]
candidates = [w for w in wrk.probe_all() if wrk.matches(job, w)]
if not candidates:
log.warning("Job %s: no worker matched (os=%r cpu=%r)", job_id, job.get("os_req"), job.get("cpu_req"))
self._append(job_id, f"[scheduler] No worker matched requirements (os='{job['os_req']}', cpu='{job['cpu_req']}').\n")
return
@@ -94,6 +98,7 @@ class Scheduler:
job_id = job["id"]
db.update_job(job_id, status="dispatching", worker_host=worker["url"],
started_at=datetime.datetime.now().isoformat())
log.info("Job %s: dispatching to %s (%s %s)", job_id, worker["url"], worker.get("os"), worker.get("cpu"))
self._append(job_id, f"[scheduler] Dispatching to {worker['url']} ({worker.get('os')} {worker.get('cpu')})\n")
try:
@@ -102,6 +107,7 @@ class Scheduler:
else:
worker_job_id = self._request_upload(job, worker)
except Exception as e:
log.error("Job %s: dispatch failed: %s", job_id, e)
db.update_job(job_id, status="failed", finished_at=datetime.datetime.now().isoformat(),
error=str(e))
self._append(job_id, f"[scheduler] FAILED: {e}\n")
@@ -116,8 +122,10 @@ class Scheduler:
self._wait_for_build(job, worker, worker_job_id)
self._fetch_artifacts(job, worker, worker_job_id)
db.update_job(job_id, status="done", finished_at=datetime.datetime.now().isoformat())
log.info("Job %s: done, artifacts saved", job_id)
self._append(job_id, "[scheduler] Build complete, artifacts saved.\n")
except Exception as e:
log.error("Job %s: failed: %s", job_id, e)
db.update_job(job_id, status="failed", finished_at=datetime.datetime.now().isoformat(),
error=str(e))
self._append(job_id, f"[scheduler] FAILED: {e}\n")