FDEBench Join us live

Q
137 / 159

Platform & multi-tenancy

An API endpoint sends an email inline and times out when the mail provider is slow. Design the background-processing system, and be specific about what can still go wrong.

question bank FDEBench bank

01
Ask

What a strong candidate asks first

Before designing anything. Skipping this is the most common way the round is lost.

  • Is it acceptable for the user to get a success response before the email is actually sent?
  • Does ordering matter between jobs for the same user?
  • Is duplicate delivery worse than delayed delivery? That sets the semantics.
  • What's the volume — does this need its own queue or share one?

02
Rubric

What earns the points

8 criteria, 100 points total. Scored independently, partial credit allowed.

Replies now, sends in background 12 pts

Records intent and returns immediately, with a worker performing the slow operation, and acknowledges the user-visible semantics change (accepted, not completed).

If you miss it You moved the work but didn't say what the user is now told. The response has changed from "sent" to "accepted" — that is a product decision, not just a refactor.
Spots the crash between writes 23 pts

Identifies the trap in the naive version: writing the database row and then publishing to the queue is two systems with no atomicity, so a crash between them silently drops the job. Full credit requires naming the crash window, not just "use a transaction".

If you miss it Your design writes to the database and then publishes to a queue. There is a window between those two calls where a crash loses the job with no trace and no error. That gap is the whole reason this question is interesting.
Saves job and data together 15 pts

Writes state change and job record in one transaction with a relay process moving outbox rows to the queue. Credit for CDC or log-tailing as an equivalent.

If you miss it Close the gap by writing the job into the same database transaction as the state change, then relaying those rows to the queue separately. One atomic write, then delivery as a separate concern.
Stops repeats with a job key 15 pts

Accepts at-least-once delivery and enforces idempotency with a mechanism — unique job key plus a dedup table, or a conditional upsert. Saying "workers should be idempotent" with no mechanism earns half at most.

If you miss it You said the worker is idempotent without saying how. Name the key and where the dedup record lives, because at-least-once means this job will run twice for real.
Recovers jobs from dead workers 12 pts

Sets a visibility timeout above realistic worst-case duration so a crashed worker's message returns rather than vanishing, with bounded exponential-backoff retries.

If you miss it You didn't say what happens when a worker dies mid-job. A visibility timeout sized above the real worst case is what makes the message come back instead of disappearing — or being redelivered while still running.
Parks failing jobs for replay 10 pts

Routes retry-exhausted jobs to a dead letter queue so one bad message cannot block the partition, and defines a replay path.

If you miss it One malformed job will retry forever and stall everything behind it. Bound the retries, move the failure to a DLQ, and say how it gets replayed once fixed.
Separate queues per workload 8 pts

Separates queues by workload so a slow provider does not starve unrelated jobs, and caps concurrency per downstream dependency.

If you miss it One shared queue means the slow mail provider starves every other background job. Isolate by workload and cap concurrency per downstream.
States ordering, watches backlog 5 pts

Addresses ordering requirements explicitly (most queues give per-partition ordering at best) and adds queue depth plus age-of-oldest-message alerts.

If you miss it You didn't state your ordering requirement or how you'd know the queue is backing up. Age of the oldest message is the alert that catches this before customers do.

03
Flags

Red flags

Reported separately, not subtracted — this is the "what would have ended the interview" note.

  • Publishes to the queue before or after the transaction with no outbox or CDC.
  • Unbounded retries with no DLQ.
  • Claims exactly-once delivery from the queue.

—