Promise.allSettled for many Sume job statuses: isolate one failure

Check many Sume job statuses at once with Promise.allSettled so one 429 or network error is reported on its own row and does not hide the other results.

4 min readSume
All posts

Use Promise.allSettled instead of Promise.all when you check many Sume jobs together. Promise.all rejects on the first failure and discards the rest, while `allSettled` waits for every promise and gives you a status for each one. A single 429 or dropped connection then shows up on its own row, and the finished jobs still report.

Each call goes to GET /v1/jobs/{id}/status, described in the jobs and results docs. The sample prints one line per job id: terminal, the seconds to wait before the next check, or the failure reason. We ran it on Node 22.14 against a local stand-in, with one unreachable base URL to see the failure row.

Reading rate-limit hints

The authentication docs say to read ratelimit-remaining rather than count requests yourself, and to wait for retry-after (seconds, sent on a 429). The sample copies retry-after onto the error so a failed row says how long to wait. A burst of status checks counts against the same requests-per-minute budget as other calls, so cap the fan-out for large lists.

Outcome per job id (read 2026-10-08)
OutcomeHow to detectWhat to print
Terminalfulfilled, data.terminal trueterminal
Still runningfulfilled, terminal falsenext_poll_after_seconds
Rate limitedrejected, HTTP 429retry-after seconds
Network error or timeoutrejected, no HTTP statuserror message

Steps

  • Wrap one status call in an async function that throws on a non-2xx answer and attaches retry-after.
  • Give each request its own AbortSignal.timeout.
  • Map the ids to promises and await Promise.allSettled.
  • Print or store one row per id by index.
  • Re-check only the rows that were not terminal, after the longest wait.

Sample

Pass job ids as arguments: node check.mjs id1 id2. The key comes from SUME_API_KEY.

const key = process.env.SUME_API_KEY ?? "";
const base = process.env.SUME_BASE ?? "https://api.sume.com";
if (!key) throw new Error("SUME_API_KEY is empty");

async function status(id) {
  const r = await fetch(`${base}/v1/jobs/${id}/status`, {
    headers: { authorization: `Bearer ${key}` },
    signal: AbortSignal.timeout(10_000),
  });
  if (!r.ok) throw Object.assign(new Error(`HTTP ${r.status}`), { retryAfter: r.headers.get("retry-after") });
  return (await r.json()).data;
}
const ids = process.argv.slice(2);
const results = await Promise.allSettled(ids.map(status));
results.forEach((res, i) => {
  if (res.status === "fulfilled") {
    const d = res.value;
    console.log(ids[i], d.terminal ? "terminal" : `again in ${d.next_poll_after_seconds}s`);
  } else {
    const wait = res.reason.retryAfter ? `, retry-after ${res.reason.retryAfter}s` : "";
    console.log(ids[i], "failed:", res.reason.message + wait);
  }
});

Limits of the pattern

Fan-out is simple, but it is not free. Fifty simultaneous status checks hit your requests-per-minute budget in one burst, and a 429 on several rows at once means the whole group should back off together. For large lists, process ids in slices of a size you choose, wait for each slice, and then sleep for the longest next_poll_after_seconds you saw.

Also keep results by index. allSettled returns an array in the same order as the input, which is why the sample can print the id next to each outcome without extra bookkeeping. That makes the output easy to diff between two runs, and easy to feed into a dashboard or a retry list for the ids that failed.

Log the failures with the id, the HTTP status when there is one, and the wait hint, so the next person can tell a rate limit from an outage at a glance.

What Sume does not do

Sume has no documented batch status route in the pages we read, so this makes one request per job. It does not queue your status checks, and a failed row is not a failed job: the job keeps running and can be checked again.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume