Part 3 of 4 · 2 min read
Exercises
Easy
Easy 1: Run it (30 minutes)
Run python -m pytest -q and python run_all.py in code/mini-jobapi.
Done when: you report the duplicate-job count with and without a key.
Easy 2: Design the endpoints (30 minutes)
Write an OpenAPI sketch for submit, status, cancel and a webhook payload for your agent.
Done when: every response code (202, 200, 404, 409) is documented.
Easy 3: Spot the bug (30 minutes)
Make status skip the owner check and write a test that catches it.
Done when: the test fails on the bug and passes on the fix.
Hint
owner A submits, owner B asks for status; expect 404.
Medium
Medium 1: Real server (4 hours)
Wrap JobApi in FastAPI or Express with an in-memory worker thread.
Done when: curl can submit, poll and cancel, and cancel stops the worker.
Medium 2: Persistent keys (3 hours)
Store idempotency keys in SQLite with an expiry.
Done when: a retry after a process restart returns the original job.
Hint
unique index on (owner, key) and catch the conflict.
Medium 3: Webhook retries (3 hours)
Implement real backoff with jitter and a dead-letter list for events that never succeed.
Done when: a dead endpoint produces a dead-letter entry after the last attempt.
Hard
Hard 1: Proxy experiment (6 hours)
Put a 30-second proxy timeout in front of a real agent and compare sync with the job API. (I did not run this, so your numbers are the ground truth.)
Done when: you report answered requests, duplicate runs and cost.
Hard 2: Concurrent submits (6 hours)
Send the same idempotency key from 50 concurrent clients. (I did not run this.)
Done when: exactly one job exists, enforced by a database constraint rather than a check-then-insert.
Hint
insert first, handle the unique-violation by loading the existing row.
Hard 3: Webhook attack tests (6 hours)
Attempt tampering, replay and timing attacks against your receiver. (I did not run this.)
Done when: all are rejected and the comparison is constant-time.
Hint
sign over timestamp.body, not body alone.