Course contentsShow
← Node.js
Lesson 1429 of 1,98013. Error Handling and Resilient SystemsFree lesson

Handling Partial Success in Batch Operations

You will track and report which individual items failed during a bulk processing task to allow for partial retries.

In this lesson, you will learn how to design batch operations that track individual item outcomes so you can selectively retry only what failed.

When processing arrays of data—such as syncing records to a database or hitting an external API—a naive Promise.all() approach is risky: if one item fails, the entire operation rejects, leaving you in the dark about which items succeeded and which didn't. To build resilient systems, we must treat the batch not as a single unit of success, but as a collection of individual results.

Moving Beyond Promise.all()

Instead of wrapping your batch in a single try-catch, process each item individually and capture both success and failure states. A common pattern is to map your input data into an array of results that explicitly identify the status of each operation.

Consider this implementation:

async function processBatch(items) {
  const results = await Promise.all(items.map(async (item) => {
    try {
      await performTask(item);
      return { success: true, item };
    } catch (error) {
      return { success: false, item, error: error.message };
    }
  }));

  const failedItems = results
    .filter(r => !r.success)
    .map(r => r.item);

  console.log(`Processed ${items.length} items. Failures: ${failedItems.length}`);
  return { results, failedItems };
}

Why This Matters for Resilience

By returning the failedItems array, you provide your orchestrator with a clear path forward. You no longer need to re-run the entire batch, which saves bandwidth and prevents duplicate processing of already-successful records. This pattern pairs perfectly with Exponential Backoff Strategies (Lesson 25); you can pass that failedItems list directly into a retry queue to attempt them again later with an increasing delay.

Using this "result object" pattern also satisfies the requirement for Standardizing Error Types (Lesson 16), as you can map specific error classes to retryable or fatal categories within your loop. This granularity is what separates a brittle script from a production-ready resilient system.

Key Takeaway: Never treat a batch operation as an "all or nothing" event; map each task to a result object so you can isolate, log, and retry only the specific items that failed.