Skip to main content

Async job queue dashboard for Python — Sidekiq Web UI for ARQ

Project description

Worq

The Sidekiq Web UI for Python job queues.

Mount a production-grade dashboard inside your FastAPI app in two lines. Monitor jobs, retry failures, search history, track metrics — all from a single interface.

ARQ — fully tested in production. Celery and RQ adapters included in beta (community testing welcome).

Worq Dashboard

More screenshots
Queues Scheduled Jobs
Queues Scheduled
Failed Jobs Workers & Active Jobs
Failed Workers
Cron Jobs
Cron
from worq import create_dashboard
from worq.adapters.arq import ARQAdapter

app.mount("/worq", create_dashboard(ARQAdapter(redis_url="redis://localhost")))

No separate process. No external service. Your dashboard lives inside your app.


Adapter Status

Adapter Status Tested With
ARQ Stable — production-tested Real ARQ workers, multiple queues, 10K+ jobs
Celery Beta — code complete, needs real-world validation Seeded Redis data matching Celery format
RQ Beta — code complete, needs real-world validation Seeded Redis data matching RQ format
Custom SDK availableAdapterBase class + helpers Compliance test harness included

Celery and RQ adapters are architecturally sound (read the correct Redis keys, handle all statuses) but haven't been tested against real Celery/RQ workers in production. Community testing and bug reports welcome.


The Problem

Every Python job queue has the same gap: no management UI.

When a production job fails at 2 AM:

Rails developer Python developer
Opens Sidekiq UI SSHes into server
Sees the failed job Opens Redis CLI
Reads the traceback Searches for the key
Clicks Retry Writes a retry script
Done in 30 seconds Hopes it works

Flower requires a separate deployment. rq-dashboard is Flask-only and stale. ARQ has nothing.

Worq closes this gap.


What You Get

Dashboard Overview

  • 5 stat cards — Enqueued, Active, Scheduled, Failed, Complete (live-updating)
  • Active jobs — Currently executing jobs with function name, queue, running duration
  • Throughput metrics — Processed count, failure rate, average duration (last 24h)
  • Recent failures — Quick retry buttons for the last 5 failed jobs

Per-Queue Breakdown

  • Each queue listed with its own enqueued/active/scheduled/failed/complete counts
  • Total row at the bottom
  • See which queue is backed up at a glance

Job Management

  • Search by function name, status, queue, time range
  • Retry failed jobs with one click
  • Delete jobs from any state
  • Run Now — execute scheduled jobs immediately
  • Bulk operations — select up to 500 jobs, retry or delete all at once
  • Paginated — handles 100K+ jobs without performance degradation

Worker Health & Active Jobs

  • Per-queue health status (ALIVE / NO WORKERS) from ARQ health-check keys
  • Active jobs table with function, queue, and running duration
  • Color-coded badges: >60s yellow, >300s red

Cron Jobs

  • View configured cron schedules with last run and result
  • Trigger manually from the dashboard
  • Validates function names — no orphan jobs

Alerting

from worq.alerts import AlertRule, SlackTarget

dashboard = create_dashboard(
    adapter,
    alerts=[
        AlertRule(
            name="high-failure-rate",
            condition="failure_rate > 5",
            targets=[SlackTarget(webhook_url="https://hooks.slack.com/...")],
            cooldown_minutes=30,
        ),
    ],
)

Safe condition DSL — no eval(), no exec(). Whitelist parser only.

Audit Log

from worq.audit import AuditLog

dashboard = create_dashboard(
    adapter,
    allow_write=True,
    audit_log=AuditLog(redis_url="redis://localhost"),
)

Records every retry, delete, and enqueue with user identity, timestamp, and job IDs.

Authentication

from worq.auth.basic import BasicAuth, hash_password

dashboard = create_dashboard(
    adapter,
    auth=BasicAuth("admin", hash_password("secret")),
)

Or bring your own: any async (request) -> bool callable works.


Worq vs Alternatives

Feature Worq Flower (Celery) rq-dashboard
Mountable in FastAPI 2 lines Separate process Separate process
ARQ + Celery + RQ ARQ stable, Celery/RQ beta Celery only RQ only
Live updates (WebSocket) Yes (WS → SSE → polling) Polling only Polling only
Job search & filtering Full Limited Limited
Bulk retry/delete Yes (500/batch) No No
Per-queue breakdown Yes No Basic
Throughput metrics Yes No No
Cron management Yes No No
Alerting (Slack/webhook) Yes No No
Audit log Yes No No
Dark mode Yes No No
Mobile responsive Yes Partial No
Pagination Yes Limited No
JSON only (no pickle) Yes Pickle default Pickle default
Security headers Yes No No

Install

pip install worq-dashboard[ui]              # Dashboard + ARQ (production-ready)
pip install worq-dashboard[ui,celery]       # + Celery adapter (beta)
pip install worq-dashboard[ui,rq]           # + RQ adapter (beta)

Note: The PyPI package is worq-dashboard but you import as from worq import ...

Requires: Python 3.12+, Redis


Quick Start

ARQ (most common)

from fastapi import FastAPI
from worq import create_dashboard
from worq.adapters.arq import ARQAdapter

app = FastAPI()
adapter = ARQAdapter(redis_url="redis://localhost:6379")
app.mount("/worq", create_dashboard(adapter))

Important: ARQ uses pickle by default. Worq requires JSON:

import json
class WorkerSettings:
    job_serializer = json.dumps
    job_deserializer = json.loads

Celery

from worq.adapters.celery import CeleryAdapter
adapter = CeleryAdapter(redis_url="redis://localhost:6379")
app.mount("/worq", create_dashboard(adapter))

RQ

from worq.adapters.rq import RQAdapter
adapter = RQAdapter(redis_url="redis://localhost:6379")
app.mount("/worq", create_dashboard(adapter))

Open http://localhost:8000/worq — that's it.


Multi-Queue Setup

adapter = ARQAdapter(
    redis_url="redis://localhost:6379",
    queue_names=["arq:queue:critical", "arq:queue:high", "arq:queue:default", "arq:queue:low"],
    allow_write=True,
)

The Queues page shows each queue separately. See which one is backed up.


Multi-Backend

Monitor ARQ and Celery from one dashboard:

dashboard = create_dashboard(
    adapters={
        "arq": ARQAdapter(redis_url="redis://localhost"),
        "celery": CeleryAdapter(redis_url="redis://localhost:6380"),
    }
)

Multi-Tenant

Separate staging and production:

dashboard = create_dashboard(
    tenants={
        "production": ARQAdapter(redis_url="redis://prod:6379"),
        "staging": ARQAdapter(redis_url="redis://staging:6379"),
    }
)

Production Ready

Worq is designed for production from day one:

  • Stateless — pure Redis reads, no in-process state. Run 100 dashboard instances behind a load balancer.
  • O(1) page loads — atomic Redis counters for complete/failed counts. No scanning at page-load time.
  • 2-second cache — in-process cache prevents redundant Redis queries from concurrent users.
  • Security headers — X-Frame-Options, X-Content-Type-Options, Referrer-Policy on every response.
  • Read-only by default — write actions require explicit allow_write=True.
  • XSS-safe — all dynamic HTML is escaped. No eval(), no exec(), no pickle.

API

Full REST API for programmatic access. Every dashboard feature is available via API.

Endpoint Description
GET /api/queues Queue stats
GET /api/queues/{queue}/jobs Job listing with status filter
GET /api/jobs/{id} Job detail
GET /api/search Search with filters
GET /api/workers Worker status
GET /api/scheduled Scheduled jobs
GET /api/failed Failed jobs
GET /api/metrics Throughput metrics
GET /api/cron Cron job list
GET /api/alerts Alert rules
GET /api/audit Audit log
POST /api/jobs/{id}/retry Retry a job
DELETE /api/jobs/{id} Delete a job
POST /api/scheduled/{id}/enqueue Run scheduled job now
POST /api/bulk/retry Bulk retry (up to 500)
POST /api/bulk/delete Bulk delete (up to 500)
POST /api/cron/{name}/trigger Trigger cron job
WS /ws/stats Live stats stream
GET /api/sse/stats SSE stats fallback

Full schemas: API Reference


Documentation

Guide What you'll learn
Getting Started Install, configure, mount — 5 minutes to first dashboard
Configuration Every create_dashboard() parameter explained
Adapters ARQ, Celery, RQ deep-dive + how to write custom adapters
Features Search, bulk ops, metrics, live updates, pagination
Authentication Basic auth, custom auth, session integration
Alerting Condition DSL, webhook/Slack targets, cooldown
Audit Log Write action tracking with user attribution
Cron Jobs View schedules, trigger manually
Multi-Backend & Multi-Tenant Multiple queues, multiple environments
ARQ Production Guide Recommended ARQ settings for production
Deployment Docker, Kubernetes, nginx, scaling
Troubleshooting Common issues and fixes
API Reference All endpoints with request/response examples
UI Guide Dark mode, mobile, accessibility, HTMX

Tech Stack

Layer Choice Why
Language Python 3.12+ Modern typing, mypy --strict
Framework FastAPI / Starlette Mountable sub-app, async native
Data Redis (async redis-py) Same store ARQ/Celery/RQ use
Models Pydantic v2 Validation + serialization
Frontend Jinja2 + HTMX Server-rendered, no JS build step
Logging structlog Structured JSON
Security JSON only No pickle, no eval, no exec

Quality

Metric Value
Tests 482 (real Redis via testcontainers)
Coverage 100% line coverage
Type safety mypy --strict, zero errors
Lint ruff, zero warnings
Accessibility WCAG 2.1 AA
License MIT

Contributing

Worq is open source under the MIT license. Issues, feature requests, and pull requests welcome.

git clone https://github.com/NitinSingh8/worq.git
cd worq
uv sync --all-extras      # Install everything
uv run pytest tests/ -v   # Run tests (needs Docker for Redis)
uv run mypy src/worq --strict

License

MIT — same as FastAPI, ARQ, and Pydantic.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

worq_dashboard-0.5.0.tar.gz (1.8 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

worq_dashboard-0.5.0-py3-none-any.whl (89.5 kB view details)

Uploaded Python 3

File details

Details for the file worq_dashboard-0.5.0.tar.gz.

File metadata

  • Download URL: worq_dashboard-0.5.0.tar.gz
  • Upload date:
  • Size: 1.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for worq_dashboard-0.5.0.tar.gz
Algorithm Hash digest
SHA256 ea5e091f696c71e0dabbb06be45085c5fabcf2c2c5f5fa8e32454233734bf590
MD5 05e70f56baaee06b1fbc1edb268d3d11
BLAKE2b-256 33a1f5d2b280b9ffc36d087030f6633f346ad26588b277a927aaf7ba6933548f

See more details on using hashes here.

File details

Details for the file worq_dashboard-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: worq_dashboard-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 89.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for worq_dashboard-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cb409bdd2750f2f4f935d050058fe2db90832b353c89d45a8ac6362516715a01
MD5 42829c29e983400fcc78259899594c1e
BLAKE2b-256 13db468c5fa08ee12091f48d48b14e802ad666c321b84f95bd71db4eaf90fa41

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page