Skip to content

Dashboard

tinyjobs dashboard --app tasks:app

serves the runbook as pages on http://127.0.0.1:8070/: an overview with the counts by queue and status, the health findings and the queued jobs by task, held ones included; the jobs, newest first, by status and queue, with every attempt and its traceback on a job's page; and the schedules. Retry, cancel, pause, resume and run are buttons that do what the CLI commands do. The pages refresh every five seconds, and /api/overview, /api/jobs, /api/jobs/<id> and /api/schedules give the same data as JSON, for curl and scripts. A page the store cannot answer within five seconds is a 503 with the error, so a probe sees the store's trouble rather than a hung page. Nothing to install: the dashboard is the standard library's HTTP server, like the metrics exporter, and it is loaded only when the command runs or the pages are mounted.

--host 0.0.0.0 exposes it, and --port moves it. There is no login and no CSRF protection, on purpose: the dashboard retries and cancels jobs, so put it behind the reverse proxy that already guards the rest of the deployment, and never on a public address. The same pages mount inside an application you already serve, at any prefix:

from tinyjobs.dashboard import asgi, wsgi
from werkzeug.middleware.dispatcher import DispatcherMiddleware

fastapi_app.mount("/tinyjobs", asgi(app))
flask_app.wsgi_app = DispatcherMiddleware(flask_app.wsgi_app, {"/tinyjobs": wsgi(app)})

asgi(app) awaits the app on the server's own event loop, so it fits beside app.lifespan(); wsgi(app) runs each request through app.run_sync, in the server's thread. Both read the prefix from the request (root_path, SCRIPT_NAME), so every link and form keeps working wherever the pages are mounted.