Skip to main content
EasyBackendBuild

Build a Simple Job Queue Processor

Implement a `JobQueue` class that processes background jobs in first-in, first-out order. Jobs move through a simple lifecycle: they start as `pending`, become `done` when their handler succeeds, or `failed` if anything...

What you will practice

PythonQueues / Background JobsAsync PatternsState MachinesError Handling

Requirements

  • Implement a `JobQueue` class in `main.py`.
  • `register_handler(job_type, fn)` registers a callable to invoke when a job of that type is processed.
  • `enqueue(job_type, payload)` adds a job with status `'pending'` to the queue and returns a unique string job ID.
  • `process_next()` takes the next pending job in FIFO order, calls its registered handler with `(payload)`, and returns the job ID. Returns `None` if the queue is empty.
  • If the handler raises any exception, the job status becomes `'failed'`. If no handler is registered for the job type, the job status also becomes `'failed'`. In both cases `process_next` must not propagate the exception.
  • `get_job(job_id)` returns a dict with keys `id`, `type`, `payload`, and `status` reflecting the current state of that job.

Starter files

main.pyEditable starter

What the judge checks

  • Runs in the python environment with the python-pytest runner.
  • Uses a 5000ms judge budget.
  • Behavior rules include: Enqueue Returns Unique Id, Process Next Runs Handler, Jobs Processed In Fifo Order, Handler Exception Marks Job Failed.

Constraints

  • Job IDs must be unique across all calls to `enqueue` within a single `JobQueue` instance.
  • Do not use any external libraries — stdlib only (`uuid`, `collections`, etc. are fine).
  • `process_next` must not raise even if the handler raises.

Example behavior

Input
q = JobQueue()
q.register_handler('email', lambda p: None)
job_id = q.enqueue('email', {'to': 'a@b.com'})
processed = q.process_next()
q.get_job(job_id)
Output
processed == job_id
{"id": job_id, "type": "email", "payload": {"to": "a@b.com"}, "status": "done"}

The handler succeeds, so the job transitions to 'done'.

Input
q.register_handler('risky', lambda p: (_ for _ in ()).throw(ValueError('boom')))
job_id = q.enqueue('risky', {})
q.process_next()
q.get_job(job_id)['status']
Output
'failed'

The handler raises an exception. process_next catches it and marks the job failed without re-raising.

Follow-up

This queue loses all jobs when the process restarts. What would you need to change to make it durable — so jobs survive a crash?