Promise.allSettled vs Promise.all for a batch of API jobs
Promise.allSettled waits for every promise and reports each outcome; Promise.all rejects on the first failure. For paid API jobs, use allSettled.

Promise.allSettled() takes an array of promises and fulfills once every one has settled, with one { status, value } or { status, reason } object per promise, in input order. Promise.all() rejects as soon as any promise rejects and gives you only that first error. Use allSettled when each task stands on its own and you need every result, which is the case when you submit a batch of paid API jobs: one failed submit must not hide the job ids of the ones that succeeded.
JavaScript facts come from MDN's Promise.allSettled() and Promise.all() pages. The job API is Sume's, from Jobs and results, Video Generation and the API reference, all read on 2026-09-29.
What is the difference between Promise.all and Promise.allSettled?
MDN puts it plainly: use allSettled() if you need the final result of every promise; all() may fit better when the tasks depend on each other or when you want to reject immediately on any failure.
| `Promise.all()` | `Promise.allSettled()` | |
|---|---|---|
| Fulfills when | Every input fulfills | Every input settles, fulfilled or rejected |
| Rejects when | Any input rejects, with the first reason | Not on an input's rejection; it waits for every input |
| Result | Array of values | Array of { status, value } or { status, reason }, in input order |
| Other promises after a failure | Not canceled; later rejections are ignored | Awaited to the end |
Why is Promise.all risky for paid API jobs?
Because a rejection doesn't stop anything. MDN notes that rejecting the returned promise does not cancel the remaining operations. The other requests are already on the wire; the ones the server accepts become jobs that run and bill, while your catch block holds a single error and none of their ids.
On Sume, every submit returns the job id in its first response, and a 2xx means the job exists and paid work is in flight. A client-side timeout does not cancel a job: it keeps running and still bills. Cancel works only before generation starts; after that the API answers 409 job_generation_already_started. So the useful move is to keep every id, not to abort the batch.
How do I handle errors with Promise.allSettled?
Map each input to a submit, then split the outcomes. Give each item an Idempotency-Key built from the item, so the retry of a rejected submit sends the same key. That matters when a submit rejected with a network error: the server may have created the job anyway, and on POST /v1/videos a replay with the same key returns the original job instead of a second one.
async function submit(item) {
const res = await fetch("https://api.sume.com/v1/videos", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SUME_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": `clip-${item.id}-v1`, // same key on every retry
},
body: JSON.stringify({ model: "sume/auto", prompt: item.prompt, aspect_ratio: "9:16", duration: 5 }),
});
const body = await res.json().catch(() => ({}));
if (!res.ok) throw Object.assign(new Error(body.error?.code ?? `HTTP ${res.status}`), { status: res.status });
return body; // 202: { id, polling_url, status }
}
const results = await Promise.allSettled(items.map(submit));
const accepted = [];
const failed = [];
results.forEach((r, i) => {
if (r.status === "fulfilled") accepted.push({ item: items[i].id, job: r.value.id });
else failed.push({ item: items[i], error: r.reason });
});
await saveJobIds(accepted); // store before anything else
// retry only failed items, with their same keys, after reading each errorDoes Promise.allSettled limit how many requests run at once?
No. items.map(submit) starts every request before allSettled is even called; it only collects the outcomes. A large batch sent this way spends the key's per-minute write budget in one burst, and on Sume it can also fill the workspace's accepted-job capacity, after which submits fail with 429 queue_full. In current code a same-key retry of a queue_full submit replays that refusal, so once jobs finish, resend those items with a new key. Cap the batch with p-limit and see video job concurrency and queueing for the numbers.
What if my process crashes before it saves the ids?
GET /v1/jobs lists jobs, filterable by status and type, so a restart can find what the lost batch created. List jobs and recover lost job ids shows how to page through them. Then poll each accepted job with backoff until its status is terminal; don't resubmit a paid request because a local process died.
Sources
Related posts
More in Developers
- Python API rate limiting: stay under a per-minute limit
Pace Python API calls with an asyncio limiter set under the API's per-minute budget, keep polling on its own budget, and back off on 429 retry-after.
- Python requests default timeout: there isn't one
Python Requests has no default timeout: without timeout= a call can hang indefinitely. Set (connect, read) on every call, and keep it short for job APIs.
- Real time speech to text API: what a file-based API can do
Sume's speech to text API isn't real time: it transcribes recordings of up to 10 minutes at a URL. Chunked recordings give near-live transcripts.
- Extract on-screen text from a reference video with an API
Reference ingest reads on-screen text at source resolution, returns lines with boxes, spans and confidence, and flags low-confidence lines instead of guessing.
Written by Sume