Skip to main content
Problem 42

Build a Simple Job Queue Processor

EASYBUILD
Queues / Background Jobs+2

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 goes wrong. There is no retry logic — a failed job stays failed.

This is the foundation. A more complex retry system (like the one in problem 0030) builds on top of exactly this shape.

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.
Examples
Example 1
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"}
Note

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

Example 2
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'
Note

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

Example 3
Input
result = q.process_next()  # called on an empty queue
Output
None
Note

Empty queue returns None.

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.
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?

Hints
Console output will appear here...