1. Courses
  2. Developer Foundations
  3. Building APIs with Node.js
  4. Stop 5

40 minIntermediate

Background jobs and idempotency

A shop owner on weak mobile data taps "Place order", the app times out, and it tries again. This lesson makes that retry safe: the slow work moves to a background job, and the order endpoint remembers each request so the same order sent twice creates one order.

By the end you can

  • Explain why a timeout cannot tell the app whether the order was created
  • Decide what the request must finish and what a background job can do later
  • Hand work to a BullMQ queue safely with a transactional outbox, and write a job that is safe to run twice
  • Build an Idempotency-Key check for POST /v1/orders that replays, rejects a changed body and handles a duplicate in flight

The everyday picture

You phone a takeaway counter to order dinner. Before you say anything, the cashier gives you a ticket number, 47. You list your order, and the line goes dead. Did they get it? You cannot know. So you call back and say, "This is ticket 47, did my order go through?"

A good counter keeps a book of ticket numbers. The cashier looks up 47, sees your order written down, and reads it back to you. Nobody cooks it twice. If you had called back without the number, the cashier would have taken a second order, and two dinners would arrive at your door.

Notice the second thing the counter does well. The cashier does not cook while you wait on the phone. She writes the ticket, says "done, 30 minutes", and the kitchen cooks in the back. Your call is short, so it is less likely to drop. An API works the same way: a ticket number the client chooses (the idempotency key), and a kitchen that works after the call ends (the background job).

A timeout does not say what happened

When the Partner app sends POST /v1/orders and gets no answer within 10 seconds, one of three things happened. The request may never have reached the API. The API may have received it and failed before saving anything. Or the API saved the order, sent 201 Created, and the answer was lost on the way back over a weak mobile connection. From the phone, all three look exactly the same: a spinner, then an error.

The app must do something. If it gives up, the shop owner may believe no order exists and phone a sales rep, who places a second one by hand. If it retries blindly, case three becomes two orders, two deliveries and two invoices. GET, PUT and DELETE are safe to repeat by HTTP's rules, but POST is not (Designing an API people can use covered the method rules, and Failure is normal covered retries from the client's side).

The fix is to make the repeat recognisable. The client sends an with the request. The server stores the key with the result. When the same key arrives again, the server returns the stored result instead of placing a new order. The operation becomes : doing it twice has the same effect as doing it once.

Partner app API + DB 1. POST, key K1 order 9041 saved 2. 201 lost timeout, 10 s 3. retry, same K1 K1 found: replay 4. 201, order 9041 one order No key: step 3 makes order 9042.
The app cannot tell a lost request from a lost answer. Because the retry carries the same key, the API finds the first result and sends it again, with the same order id.

Quick check

The Partner app's POST /v1/orders timed out after 10 seconds. What does the app know?

Loading the rest of the lesson…