Problem 42
Build a Simple Job Queue Processor
EASYBUILD
Queues / Background Jobs+2
Queues / Background JobsState MachinesError Handling
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
JobQueueclass inmain.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. ReturnsNoneif 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 casesprocess_nextmust not propagate the exception. get_job(job_id)returns a dict with keysid,type,payload, andstatusreflecting 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
enqueuewithin a singleJobQueueinstance. - Do not use any external libraries — stdlib only (
uuid,collections, etc. are fine). process_nextmust 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...