Cancellation
Cancellation through AbortSignal, checked before, between, and during retries.
AbortSignal cancels retries, checked before, between, and during attempts. runRetryPolicy(...) accepts an AbortSignal through the signal option. Use it to stop retrying on user navigation, request timeouts, shutdown, or parent workflow cancellation.
Basic Usage
Pass controller.signal to runRetryPolicy(...); aborting the controller stops the run with an AbortError.
import { AbortError, exponentialBackoff, runRetryPolicy } from "@zap-studio/retry";
const controller = new AbortController();
const policy = exponentialBackoff({
maxAttempts: 5,
baseDelayMs: 100,
maxDelayMs: 2_000,
});
const promise = runRetryPolicy(
policy,
async () => {
return await doWork();
},
{ signal: controller.signal },
);
controller.abort(new Error("Request canceled by user"));
try {
await promise;
} catch (error) {
if (error instanceof AbortError) {
console.error("Retry aborted:", error.message);
}
}
Throw Mode
In the default throw mode, an aborted run rejects with AbortError.
import { AbortError, runRetryPolicy } from "@zap-studio/retry";
const controller = new AbortController();
try {
await runRetryPolicy(
policy,
async () => {
return await doWork();
},
{ signal: controller.signal },
);
} catch (error) {
if (error instanceof AbortError) {
console.error("Retry aborted:", error.message);
} else {
throw error;
}
}
Non-Throw Mode
With throwOnExhausted: false, an abort resolves to { ok: false } with the AbortError on result.error instead of throwing.
const controller = new AbortController();
const result = await runRetryPolicy(
policy,
async () => {
return await doWork();
},
{
signal: controller.signal,
throwOnExhausted: false,
},
);
if (result.ok) {
console.log(result.value);
} else {
console.error("Retry stopped:", result.error);
}
Cancellation Timing
The runner checks the signal:
- before each attempt starts
- after a failed attempt, before consulting the policy
- while waiting between retries (the delay is raced against the signal)
This keeps cancellation responsive without custom orchestration code.
Abort Reasons
The abort reason you pass to controller.abort(...) is normalized into the AbortError:
- an
Errorreason becomes theAbortErrormessage, with the original error oncause - a non-empty string reason becomes the message
- no reason produces the message
"Retry aborted."
See Structured Errors for the full AbortError reference.