Six actors hand one submission along in nine steps, from the student pressing Submit to the result on their screen. Postgres stays the single source of truth; the queue only ever carries a small reference (job ID, kind, HMAC token). Locally, a thread pool inside the relay stands in for SQS and Lambda and runs the same handler code.
Stage 3 (current): SQS and Lambda in production; local transport in dev. Languages on this pipeline: Python and JavaScript. Celery + Redis remain only for plagiarism, AI tasks and scheduled jobs.Handed over
Why it works this way
If something goes wrong
Job row in Postgres
A job gets three claims. If it still has no result, it becomes dead and its submission error, which doesn't count against the student's attempts. codemas-exec-dlq holds messages whose delivery wasn't acknowledged 3 times. Causes: crashes and timeouts; Django unreachable; a claim refused with 401, 404 or busy; a failed /fail/ call; a complete answered with anything but 200 or 409; and claims skipped for lack of time. A job released through /fail/ has its message acknowledged, so it dies in Postgres with no message in the DLQ.
14 steps · 3 phases · triggered once at exam close, runs entirely in background