Web¶
Admin UI and progress streaming routers.
taskq.web is an empty module (docstring only) — it renders no members. The directives
below target the concrete submodules instead. See also the Admin UI guide
and Progress & Streaming guide for task-oriented walkthroughs.
Progress SSE router¶
progress ¶
FastAPI router: SSE progress bridge and poll-state endpoint.
Bridges Redis pub/sub progress events to Server-Sent Events for browsers and
API clients. Mount at prefix="/jobs" to produce the canonical URLs:
GET /jobs/api/job/{job_id}/progress/stream — SSE stream
GET /jobs/api/job/{job_id}/state — poll-state (JSON)
Importing this module requires the taskq[fastapi] optional extra (which
includes sse-starlette).
Design notes¶
- Subscribe-before-query: the Redis channel is subscribed BEFORE the PG snapshot read to eliminate the race window where an event published between the PG read and the subscribe would be silently lost.
- The PG connection is released immediately after the initial row fetch; no PG connection is held during streaming.
- The Redis subscribe and PG query happen in the handler body (before
EventSourceResponseis created) so that 404/503 errors produce proper HTTP status codes rather than appearing inside an already-started SSE stream. - Keepalive comments are emitted every
sse_heartbeat_intervalseconds via aget_message(timeout=...)polling loop (avoids blockinglisten()which has no per-message timeout support). - On client disconnect,
try/finallyin the generator callspubsub.unsubscribe()andpubsub.aclose()to prevent stale Redis subscriptions.
create_router ¶
create_router(
pg_pool: Pool,
redis_client: Any,
*,
schema: str = "taskq",
auth_dependency: Callable[..., Any] | None = None,
sse_heartbeat_interval: timedelta = timedelta(
seconds=15
),
) -> APIRouter
Return a FastAPI APIRouter exposing the SSE progress bridge.
Mount at prefix="/jobs" to produce the canonical paths::
GET /jobs/api/job/{job_id}/progress/stream
GET /jobs/api/job/{job_id}/state
Parameters¶
pg_pool:
asyncpg connection pool for snapshot reads and poll-state queries.
redis_client:
redis.asyncio.Redis instance, or None when Redis is not
configured. If None, the SSE endpoint returns HTTP 503.
schema:
PostgreSQL schema name (default "taskq").
auth_dependency:
Optional FastAPI dependency callable; if provided it is injected via
Depends() on all routes (same pattern as
taskq.web.admin.create_router).
sse_heartbeat_interval:
Cadence for ': keepalive' SSE comments (default 15 s).
Source code in src/taskq/web/progress.py
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 | |
Admin UI router factory¶
_factory ¶
Admin UI router factory: Jinja2 setup, auth hook, route registration.
Importing this module requires the taskq[fastapi] optional extra.
GZipStaticOnly ¶
Bases: GZipMiddleware
GZip only static assets (/static/*), not HTML or JSON responses.
__call__
async
¶
Source code in src/taskq/web/admin/_factory.py
AdminBundle
dataclass
¶
AdminBundle(
router: APIRouter,
templates: Environment,
pg_pool: Pool,
schema: str,
redis_client: Any | None,
settings: TaskQSettings,
base_path: str,
backend: Backend | None = None,
)
Returned by create_router(); contains the router and all app.state values.
Pass this to setup_admin_state(app, bundle) in your lifespan before
the first request, then mount bundle.router via app.include_router.
get_realtime_mode
async
¶
Return (realtime_mode, mode_label) using a 5 s server-side cache.
realtime_mode ∈ {"realtime", "polling", "polling-degraded"}. Cache is module-level — one entry covers all admin UI routes on the same process.
Source code in src/taskq/web/admin/_factory.py
get_pg_pool ¶
get_backend ¶
get_schema ¶
get_redis_client ¶
get_templates ¶
get_settings ¶
get_realtime_ctx
async
¶
Dependency: returns (realtime_mode, mode_label) for template rendering.
get_base_path ¶
get_csrf_token ¶
Dependency: returns the CSRF token.
Prefers the token set by _CsrfRoute via request.state
so the form hidden field and the cookie always carry the same value.
Falls back to the cookie (present from a prior GET), then generates
a fresh token.
Source code in src/taskq/web/admin/_factory.py
validate_csrf
async
¶
Dependency: validates the synchronizer-token CSRF on POST requests.
Source code in src/taskq/web/admin/_factory.py
setup_admin_state ¶
Populate app.state from bundle so route handler dependencies resolve.
Call this in your FastAPI lifespan after creating the bundle and before the first request arrives.
Source code in src/taskq/web/admin/_factory.py
create_router ¶
create_router(
pg_pool: Pool,
*,
schema: str = "taskq",
redis_client: Any | None = None,
auth_dependency: Callable[..., Any] | None = None,
base_path: str = "",
backend: Backend | None = None,
) -> AdminBundle
Create the admin UI FastAPI router.
Route handlers access shared resources (pool, schema, redis, settings,
templates) via Depends(get_pg_pool) etc., which read from
request.app.state. Call setup_admin_state(app, bundle) in your
lifespan to populate those keys, then mount bundle.router at your
chosen prefix via app.include_router.
base_path must match the prefix passed to include_router (e.g.
"/admin"). It is injected as a Jinja2 global so templates can build
prefix-safe URLs with {{ base_path }}/queues etc.
Source code in src/taskq/web/admin/_factory.py
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | |
Health router¶
health ¶
FastAPI router for /jobs/health/{live,ready}.
GET /jobs/health/metrics is served by taskq.contrib.prometheus.create_metrics_router (requires taskq[prometheus]) and must be mounted alongside this router.
Importing this module requires the taskq[fastapi] optional extra.
create_health_router ¶
Create a FastAPI router at /jobs/health/{live,ready}.
Captures deps via closure — no FastAPI dependency injection. Mount alongside create_metrics_router (taskq.contrib.prometheus) for the full /jobs/health surface including Prometheus metrics.