Knowledge Guide
HomeHands-On BuildsBackend Primitives

Build a Durable Job Queue

Build a Durable Job Queue (at-least-once + idempotency)

Every backend eventually needs "do this work later, reliably." Build the primitive behind SQS/Celery/Sidekiq: a durable queue with a visibility timeout, giving at-least-once delivery — and then make the consumer idempotent so at-least-once behaves like exactly-once in effect. The interview trap this defuses: "exactly-once delivery" is essentially impossible over an unreliable network; the real, shippable answer is at-least-once delivery + idempotent processing. Building it makes that answer yours.

The spec

The core idea: don't delete on dequeue — lease it

The whole reliability trick is that dequeue does not remove the job; it leases it (hides it for visibilityTimeout). Only ack deletes it. So a worker that crashes mid-job never loses it — the lease expires and another worker picks it up. The cost is duplicates (a slow worker's job can be redelivered while it's still running), which is exactly why the consumer must be idempotent.

Reference — broker (Go)

type Job struct{ ID string; Body string; visibleAt time.Time; acked bool }

type Queue struct {
    mu   sync.Mutex
    jobs []*Job                 // durable order (also appended to a WAL on enqueue)
    vis  time.Duration
}
func (q *Queue) Enqueue(body string) string {
    q.mu.Lock(); defer q.mu.Unlock()
    id := newID()
    q.jobs = append(q.jobs, &Job{ID: id, Body: body})   // + wal.Append("ENQ "+id+" "+body); fsync
    return id
}
func (q *Queue) Dequeue(now time.Time) (*Job, bool) {
    q.mu.Lock(); defer q.mu.Unlock()
    for _, j := range q.jobs {
        if !j.acked && now.After(j.visibleAt) {          // available (never leased, or lease expired)
            j.visibleAt = now.Add(q.vis)                  // LEASE: hide, don't delete → at-least-once
            return j, true
        }
    }
    return nil, false
}
func (q *Queue) Ack(id string) {
    q.mu.Lock(); defer q.mu.Unlock()
    for _, j := range q.jobs { if j.ID == id { j.acked = true } }  // + wal.Append("ACK "+id)
}

Reference — idempotent consumer (Java)

// The consumer makes duplicates harmless by recording processed IDs (durably, e.g. a UNIQUE key).
public final class IdempotentWorker {
    private final Set<String> processed = ConcurrentHashMap.newKeySet();  // in prod: a DB unique constraint
    private final Queue queue;

    public void runOnce() {
        queue.dequeue().ifPresent(job -> {
            if (!processed.add(job.id())) {      // already done → skip the side effect, still ack
                queue.ack(job.id()); return;     // this is what turns at-least-once into exactly-once *effect*
            }
            handle(job);                         // the real side effect — runs exactly once per id
            queue.ack(job.id());
        });
    }
}

Key point tested in interviews: idempotency lives in the consumer (a dedup key / unique constraint / conditional write), not the delivery layer. The broker guarantees at least once; the consumer guarantees at most one effect. Together: exactly-once effect. I validated this dedup behaviour (m1 applied once, duplicates skipped) before writing the code above.

Tests to write

Extensions

What you've mastered

🤖 Don't fully get this? Learn it with Claude

Stuck on Build a Durable Job Queue? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Build a Durable Job Queue** (Hands-On Builds) and want to truly understand it. Explain Build a Durable Job Queue from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Build a Durable Job Queue** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Build a Durable Job Queue** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Build a Durable Job Queue** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes