Dev.to WebDev 🛠 Dev 👁 0 📖 1 min read

Why Promise.all() Almost Broke Our Order Pipeline

We had a bug that only showed up when a third-party service went down — not our code. That's always a fun one to debug. The setup On every order, our API kicked off five async tasks in parallel: await Prom

Why Promise.all() Almost Broke Our Order Pipeline

We had a bug that only showed up when a third-party service went down — not our code. That's always a fun one to debug.

The setup

On every order, our API kicked off five async tasks in parallel:

await Promise.all([
  sendConfirmationEmail(order),
  updateInventory(order),
  generateInvoice(order),
  notifyWarehouse(order),
  createAuditLog(order),
]);

Simple, readable, and totally wrong for this use case — we just didn't know it yet.

The failure mode

Promise.all() short-circuits: the instant any promise rejects, it rejects immediately and the rest are left dangling. So when our email provider had a temporary outage, this happened:

  • ❌ Inventory update — never ran
  • ❌ Warehouse notification — never ran
  • ❌ Audit log — never ran

Meanwhile, the order was already confirmed and paid for. The customer just saw... nothing. No inventory change, no warehouse ping, no trace in the audit log. One unrelated service failure took down four unrelated tasks.

comparison_diagram

The fix: Promise.allSettled()

const results = await Promise.allSettled([
  sendConfirmationEmail(order),
  updateInventory(order),
  generateInvoice(order),
  notifyWarehouse(order),
  createAuditLog(order),
]);

const failed = results.filter(
  result => result.status === "rejected"
);

// handle/retry `failed` independently

allSettled() always resolves once every promise finishes, giving you a status of "fulfilled" or "rejected" for each one. No more all-or-nothing behavior.

Result:

  • ✅ Inventory still updates
  • ✅ Warehouse still gets notified
  • ✅ Audit logs still get written
  • ✅ Only the failed task gets queued for retry

Takeaway

Promise.all() is great when every task genuinely depends on all the others succeeding. But for independent side effects — email, logging, notifications — allSettled() is almost always the safer default. One flaky dependency shouldn't get veto power over four healthy ones.

Curious — have you been bitten by this before? Where else have you seen Promise.all() used when allSettled() should've been the call?

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.