Every reactive strategy (retry, circuit breaker, hedging, fallback) asks one question about each outcome: is this a
failure I should handle? The answer comes from its shouldHandle option. The defaults are deliberately narrow:
handle transient failures, leave everything else alone.
Client errors. A 400 or 404 means the request is wrong, not that the dependency is down. Retrying won’t help,
and counting it would let bad input open the breaker. 408 and 429 are the dependency pushing back, so they behave
like 5xx.
Rejections. The call never started, so it says nothing about the dependency. A breaker that counted its own
CIRCUIT_OPEN rejections would never close. Fallback does handle them: serving a cached value when the circuit
is open is its main job.
Aborts. Nobody is waiting for the answer. A timeout is not a caller abort, though: a TimeoutRejectedError
is handled like any other transient error.
Results. A resolved promise is a success unless you say otherwise with handleResult.
A numeric status, statusCode or response.status in 400–499, except 408 and 429
isClientError(e)
Rejection
Raised by a strategy that refused to start the call (CallRejectedError subclasses)
isRejection(e)
Abort
error.name === 'AbortError', or any error once the caller aborted the execution’s signal
isAbortError(e) (name check only)
The status check is duck-typed, so it works with fetch wrappers, axios errors, and the AWS and Google SDKs. Throw your
own error with a status property and the defaults apply:
The ok read-only property of the Response interface contains a Boolean stating whether the response was successful (status in the range 200-299) or not.
Retry never retries an open circuit (CIRCUIT_OPEN / CIRCUIT_ISOLATED), whatever shouldHandle says.
A circuit breaker never counts rejections, and an error it doesn’t handle is neither a failure nor a success.
Only a handled outcome counts as a failure; only an unhandled successful outcome counts as a success.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
ResiliencePipelineBuilder<
interfaceResponse
The Response interface of the Fetch API represents the response to a request.
The error is an instance of Type (and predicate returns true)
handleInner(Type, predicate?)
The error or any error in its cause chain (10 levels deep) is a Type
handleResult(predicate)
A successful result for which predicate returns true
The clauses are OR-ed. A function predicate receives { outcome, context } (retry adds attemptNumber) and may be
async. To extend the default instead of replacing it, call it:
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
ResiliencePipelineBuilder<
interfaceResponse
The Response interface of the Fetch API represents the response to a request.
Default for retry, circuit breaker and hedging: transient failures only.
Not handled: results, aborts, client errors (4xx except 408/429), rejections from other strategies.
When the last attempt still produces a handled result (say, a 503 Response), retry returns that result. It
doesn’t throw. Check the status after execute(), or throw inside the callback as in the HttpError example above.
Throw (or wrap an error in) this to stop retrying right away: retry gives up and the caller receives the original error.
Like p-retry's AbortError. throw new NonRetryableError(error) or throw new NonRetryableError('invalid card').