UNPKG

@apollo/client

Version:

A fully-featured caching GraphQL client.

123 lines (122 loc) 4.52 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RetryLink = void 0; const rxjs_1 = require("rxjs"); const errors_1 = require("@apollo/client/errors"); const link_1 = require("@apollo/client/link"); const delayFunction_js_1 = require("./delayFunction.cjs"); const retryFunction_js_1 = require("./retryFunction.cjs"); class RetryableOperation { observer; operation; forward; delayFor; retryIf; retryCount = 0; currentSubscription = null; timerId; constructor(observer, operation, forward, delayFor, retryIf) { this.observer = observer; this.operation = operation; this.forward = forward; this.delayFor = delayFor; this.retryIf = retryIf; this.try(); } /** * Stop retrying for the operation, and cancel any in-progress requests. */ cancel() { if (this.currentSubscription) { this.currentSubscription.unsubscribe(); } clearTimeout(this.timerId); this.timerId = undefined; this.currentSubscription = null; } try() { this.currentSubscription = this.forward(this.operation).subscribe({ next: (result) => { if ((0, errors_1.graphQLResultHasProtocolErrors)(result)) { this.onError(result.extensions[errors_1.PROTOCOL_ERRORS_SYMBOL], () => // Pretend like we never encountered this error and move the result // along for Apollo Client core to handle this error. this.observer.next(result)); // Unsubscribe from the current subscription to prevent the `complete` // handler to be called as a result of the stream closing. this.currentSubscription?.unsubscribe(); return; } this.observer.next(result); }, error: (error) => this.onError(error, () => this.observer.error(error)), complete: this.observer.complete.bind(this.observer), }); } onError = async (error, onContinue) => { this.retryCount += 1; const errorLike = (0, errors_1.toErrorLike)(error); const shouldRetry = await this.retryIf(this.retryCount, this.operation, errorLike); if (shouldRetry) { this.scheduleRetry(this.delayFor(this.retryCount, this.operation, errorLike)); return; } onContinue(); }; scheduleRetry(delay) { if (this.timerId) { throw new Error(`RetryLink BUG! Encountered overlapping retries`); } this.timerId = setTimeout(() => { this.timerId = undefined; this.try(); }, delay); } } /** * `RetryLink` is a non-terminating link that attempts to retry operations that * fail due to network errors. It enables resilient GraphQL operations by * automatically retrying failed requests with configurable delay and retry * strategies. * * @remarks * * `RetryLink` is particularly useful for handling unreliable network conditions * where you would rather wait longer than explicitly fail an operation. It * provides exponential backoff and jitters delays between attempts by default. * * > [!NOTE] * > This link does not handle retries for GraphQL errors in the response. Use * > `ErrorLink` to retry an operation after a GraphQL error. For more * > information, see the [Error handling documentation](https://apollographql.com/docs/react/data/error-handling#on-graphql-errors). * * @example * * ```ts * import { RetryLink } from "@apollo/client/link/retry"; * * const link = new RetryLink(); * ``` */ class RetryLink extends link_1.ApolloLink { delayFor; retryIf; constructor(options) { super(); const { attempts, delay } = options || {}; this.delayFor = typeof delay === "function" ? delay : (0, delayFunction_js_1.buildDelayFunction)(delay); this.retryIf = typeof attempts === "function" ? attempts : (0, retryFunction_js_1.buildRetryFunction)(attempts); } request(operation, forward) { return new rxjs_1.Observable((observer) => { const retryable = new RetryableOperation(observer, operation, forward, this.delayFor, this.retryIf); return () => { retryable.cancel(); }; }); } } exports.RetryLink = RetryLink; //# sourceMappingURL=retryLink.cjs.map