### Install p-retry Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md Install the p-retry package using npm. ```sh npm install p-retry ``` -------------------------------- ### Making a function retriable with makeRetriable Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md Wrap a function with `makeRetriable` to automatically retry its calls on failure. This example sets up `fetch` to retry up to 5 times. ```javascript import {makeRetriable} from 'p-retry'; const fetchWithRetry = makeRetriable(fetch, {retries: 5}); const response = await fetchWithRetry('https://sindresorhus.com/unicorn'); ``` -------------------------------- ### Basic pRetry Usage with Fetch Source: https://context7.com/sindresorhus/p-retry/llms.txt Demonstrates how to use pRetry to automatically retry a fetch request. It includes an example of throwing an AbortError to stop retries for specific conditions like a 404 response. ```javascript import pRetry, {AbortError} from 'p-retry'; // Basic usage - fetch with automatic retries const fetchData = async () => { const response = await fetch('https://api.example.com/data'); // Abort retrying if resource doesn't exist (no point retrying 404) if (response.status === 404) { throw new AbortError(response.statusText); } if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return response.json(); }; // Execute with 5 retries const data = await pRetry(fetchData, {retries: 5}); console.log(data); // Output: { ... fetched JSON data ... } ``` -------------------------------- ### Aborting retries with AbortController Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md Abort retrying by passing an `AbortSignal` to the `signal` option. This example shows how to abort on a button click. ```javascript import pRetry from 'p-retry'; const run = async () => { … }; const controller = new AbortController(); cancelButton.addEventListener('click', () => { controller.abort(new Error('User clicked cancel button')); }); try { await pRetry(run, {signal: controller.signal}); } catch (error) { console.log(error.message); //=> 'User clicked cancel button' } ``` -------------------------------- ### Basic p-retry usage with shouldConsumeRetry Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md Use the `shouldConsumeRetry` option to conditionally consume a retry attempt. In this example, `RateLimitError`s do not decrement the available retries. ```javascript import pRetry from 'p-retry'; const run = async () => { … }; const result = await pRetry(run, { retries: 2, shouldConsumeRetry: ({error, retriesLeft}) => !(error instanceof RateLimitError) }); ``` -------------------------------- ### Basic Usage with AbortError Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md Retry an async function and abort retrying if a 404 status code is encountered. This example demonstrates how to use `AbortError` to stop retries for specific conditions. ```js import pRetry, {AbortError} from 'p-retry'; const run = async () => { const response = await fetch('https://sindresorhus.com/unicorn'); // Abort retrying if the resource doesn't exist if (response.status === 404) { throw new AbortError(response.statusText); } return response.blob(); }; console.log(await pRetry(run, {retries: 5})); ``` -------------------------------- ### Stopping retries on SIGINT Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md Handle process signals like SIGINT (Ctrl+C) by using an `AbortController`. This example aborts retries when SIGINT is received. ```javascript import pRetry from 'p-retry'; const controller = new AbortController(); process.once('SIGINT', () => { controller.abort(new Error('SIGINT received')); }); try { await pRetry(run, {signal: controller.signal}); } catch (error) { console.log('Retry stopped due to:', error.message); } ``` -------------------------------- ### Passing arguments to the retried function Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md To pass arguments to the function being retried, wrap it in an inline arrow function. This example shows how to call `run` with the '🦄' emoji. ```javascript import pRetry from 'p-retry'; const run = async emoji => { // … }; // Without arguments await pRetry(run, {retries: 5}); // With arguments await pRetry(() => run('🦄'), {retries: 5}); ``` -------------------------------- ### onFailedAttempt with Delay Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md Use the `onFailedAttempt` callback to introduce a delay before retrying an operation. This example uses the `delay` package to pause execution for 1 second after a failed attempt. ```js import pRetry from 'p-retry'; import delay from 'delay'; const run = async () => { … }; const result = await pRetry(run, { onFailedAttempt: async () => { console.log('Waiting for 1 second before retrying'); await delay(1000); } }); ``` -------------------------------- ### Custom shouldRetry Logic Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md Define a custom function to determine whether a retry should occur based on the error and retry context. This example retries all errors except those of type `CustomError`. ```js import pRetry from 'p-retry'; const run = async () => { … }; const result = await pRetry(run, { shouldRetry: ({error, attemptNumber, retriesLeft}) => !(error instanceof CustomError) }); ``` -------------------------------- ### Cancel Retry Operations with AbortController Source: https://context7.com/sindresorhus/p-retry/llms.txt Use AbortController to cancel pending retry operations. The promise rejects with the abort reason when aborted. This example shows cancellation on user action and on SIGINT in Node.js. ```javascript import pRetry from 'p-retry'; // Cancel on user action const controller = new AbortController(); const fetchButton = document.getElementById('fetch'); const cancelButton = document.getElementById('cancel'); fetchButton.addEventListener('click', async () => { try { const result = await pRetry( async () => { const response = await fetch('https://api.example.com/slow-endpoint'); if (!response.ok) throw new Error('Failed'); return response.json(); }, { retries: 10, signal: controller.signal } ); console.log('Success:', result); } catch (error) { if (error.name === 'AbortError') { console.log('Request cancelled by user'); } else { console.error('Request failed:', error.message); } } }); cancelButton.addEventListener('click', () => { controller.abort(new Error('User cancelled')); }); // Cancel on SIGINT (Node.js) const nodeController = new AbortController(); process.once('SIGINT', () => { nodeController.abort(new Error('SIGINT received')); }); try { await pRetry(longRunningOperation, {signal: nodeController.signal}); } catch (error) { console.log('Stopped:', error.message); } ``` -------------------------------- ### Testing with Mocked Timers Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md Guidance on mocking timers for testing. ```APIDOC ## FAQ: Mocking Timers for Testing The package uses `setTimeout` and `clearTimeout` from the global scope, so you can use the [Node.js test timer mocking](https://nodejs.org/api/test.html#class-mocktimers) or a package like [`sinon`](https://github.com/sinonjs/sinon). ```js // Example using Node.js test timer mocking import test from 'node:test'; import assert from 'node:assert'; import pRetry from 'p-retry'; test('should retry with mocked timers', async (t) => { let attempts = 0; tconst run = async () => { attempts++; if (attempts < 3) { throw new Error('Failed attempt'); } return 'Success'; }; tawait t.test('mock timers', async (mock) => { mock.timers.enable(); const promise = pRetry(run, { retries: 2 }); await mock.timers.tick(2000); // Advance timers to trigger retries const result = await promise; assert.strictEqual(result, 'Success'); assert.strictEqual(attempts, 3); mock.timers.disable(); }); }); ``` ``` -------------------------------- ### Advanced pRetry Configuration Source: https://context7.com/sindresorhus/p-retry/llms.txt Illustrates advanced configuration options for pRetry, including setting the number of retries, exponential backoff factor, minimum and maximum delay between retries, randomization, and a total time budget for retries. ```javascript const result = await pRetry( async (attemptNumber) => { console.log(`Attempt ${attemptNumber}`); const response = await fetch('https://api.example.com/resource'); if (!response.ok) throw new Error('Request failed'); return response.json(); }, { retries: 5, // Maximum 5 retry attempts (default: 10) factor: 2, // Exponential factor (default: 2) minTimeout: 1000, // Initial delay: 1 second (default: 1000) maxTimeout: 30000, // Max delay between retries: 30 seconds (default: Infinity) randomize: true, // Add jitter to delays (default: false) maxRetryTime: 60000, // Total time budget: 60 seconds (default: Infinity) } ); ``` -------------------------------- ### pRetry with onFailedAttempt Callback Source: https://context7.com/sindresorhus/p-retry/llms.txt Shows how to use the `onFailedAttempt` callback to log retry attempts and display information about the error, attempt number, retries left, and the delay before the next retry. ```javascript import pRetry from 'p-retry'; const fetchWithLogging = async () => { const response = await fetch('https://api.example.com/data'); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return response.json(); }; const result = await pRetry(fetchWithLogging, { retries: 5, onFailedAttempt: ({error, attemptNumber, retriesLeft, retriesConsumed, retryDelay}) => { console.log(`Attempt ${attemptNumber} failed: ${error.message}`); console.log(`Retrying in ${retryDelay}ms. ${retriesLeft} retries left.`); // Attempt 1 failed: HTTP 503 // Retrying in 1000ms. 5 retries left. // Attempt 2 failed: HTTP 503 // Retrying in 2000ms. 4 retries left. } }); ``` -------------------------------- ### Handling SIGINT (Ctrl+C) Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md How to stop retries when the process receives SIGINT. ```APIDOC ## FAQ: Handling SIGINT (Ctrl+C) Use an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) to signal cancellation on SIGINT, and pass its `signal` to `pRetry`: ```js import pRetry from 'p-retry'; const controller = new AbortController(); process.once('SIGINT', () => { controller.abort(new Error('SIGINT received')); }); const run = async () => { // Your async operation here }; try { await pRetry(run, {signal: controller.signal}); } catch (error) { console.log('Retry stopped due to:', error.message); } ``` The package does not handle process signals itself to avoid global side effects. ``` -------------------------------- ### Wrap Functions for Automatic Retries with makeRetriable Source: https://context7.com/sindresorhus/p-retry/llms.txt Use `makeRetriable` to create a retry-enabled version of a function. This is useful for existing functions where you don't want to modify call sites. Configuration options like `retries`, `minTimeout`, `onFailedAttempt`, `factor` can be passed. ```javascript import {makeRetriable} from 'p-retry'; // Wrap fetch for automatic retries const fetchWithRetry = makeRetriable(fetch, { retries: 3, minTimeout: 500, onFailedAttempt: ({attemptNumber, error}) => { console.log(`Fetch attempt ${attemptNumber} failed: ${error.message}`); } }); // Use like normal fetch - retries are automatic const response = await fetchWithRetry('https://api.example.com/data'); const data = await response.json(); // Wrap a custom async function async function uploadFile(file, endpoint) { const formData = new FormData(); formData.append('file', file); const response = await fetch(endpoint, { method: 'POST', body: formData }); if (!response.ok) { throw new Error(`Upload failed: ${response.status}`); } return response.json(); } const uploadWithRetry = makeRetriable(uploadFile, { retries: 5, factor: 2, minTimeout: 2000 }); // All arguments are passed through const result = await uploadWithRetry(myFile, 'https://api.example.com/upload'); console.log('Upload successful:', result); ``` -------------------------------- ### pRetry Function Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md The main pRetry function takes an input function and an optional options object to configure retry behavior. ```APIDOC ## pRetry(input, options?) ### Description Returns a `Promise` that is fulfilled when calling `input` returns a fulfilled promise. If calling `input` returns a rejected promise, `input` is called again until the max retries are reached, it then rejects with the last rejection reason. Does not retry on most `TypeErrors`, with the exception of network errors. This is done on a best case basis as different browsers have different [messages](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful) to indicate this. See [whatwg/fetch#526 (comment)](https://github.com/whatwg/fetch/issues/526#issuecomment-554604080) Non-network `TypeError`s always abort retries, even if `shouldConsumeRetry` or `shouldRetry` would otherwise allow another attempt. ### Parameters #### input Type: `Function` Receives the number of attempts as the first argument and is expected to return a `Promise` or any value. #### options Type: `object` ##### onFailedAttempt(context) Type: `Function` Callback invoked on each failure. Receives a context object containing the error and retry state information. The function is called _after_ `shouldConsumeRetry` and _before_ `shouldRetry`, for all errors _except_ `AbortError`. If the function throws, all retries will be aborted and the original promise will reject with the thrown error. ```js import pRetry from 'p-retry'; const run = async () => { const response = await fetch('https://sindresorhus.com/unicorn'); if (!response.ok) { throw new Error(response.statusText); } return response.json(); }; const result = await pRetry(run, { onFailedAttempt: ({error, attemptNumber, retriesLeft, retriesConsumed, retryDelay}) => { console.log(`Attempt ${attemptNumber} failed. Retrying in ${retryDelay}ms. ${retriesLeft} retries left.`); // 1st request => Attempt 1 failed. Retrying in 1000ms. 5 retries left. // 2nd request => Attempt 2 failed. Retrying in 2000ms. 4 retries left. // … }, retries: 5 }); console.log(result); ``` The `context` object contains: - `error` - The error that was thrown - `attemptNumber` - The attempt number (starts at 1) - `retriesLeft` - Number of retries remaining - `retriesConsumed` - Number of retries consumed so far - `retryDelay` - The delay in milliseconds before the next retry (based on `minTimeout`, `factor`, `maxTimeout`, and `randomize`). This is `0` when the retry is skipped or when no retry will occur based on the checks completed before the current callback runs. The `onFailedAttempt` function can return a promise. For example, to add a [delay](https://github.com/sindresorhus/delay): ```js import pRetry from 'p-retry'; import delay from 'delay'; const run = async () => { … }; const result = await pRetry(run, { onFailedAttempt: async () => { console.log('Waiting for 1 second before retrying'); await delay(1000); } }); ``` ##### shouldRetry(context) Type: `Function` Decide if a retry should occur based on context. Returning `true` triggers a retry, `false` aborts with the error. The function is called _after_ `onFailedAttempt` and `shouldConsumeRetry`. The function is _not_ called on `AbortError`, `TypeError` (except network errors), or if `retries` or `maxRetryTime` are exhausted. If the function throws, all retries will be aborted and the original promise will reject with the thrown error. ```js import pRetry from 'p-retry'; const run = async () => { … }; const result = await pRetry(run, { shouldRetry: ({error, attemptNumber, retriesLeft}) => !(error instanceof CustomError) }); ``` In the example above, the operation will be retried unless the error is an instance of `CustomError`. ``` -------------------------------- ### Immediate Retry Abort with `AbortError` Source: https://context7.com/sindresorhus/p-retry/llms.txt Use `AbortError` to immediately stop all retries for permanent errors like 404 or 400. It can be thrown directly or wrap an existing `Error` object. ```javascript import pRetry, {AbortError} from 'p-retry'; const fetchUser = async (userId) => { const response = await fetch(`https://api.example.com/users/${userId}`); // 404 - User doesn't exist, no point retrying if (response.status === 404) { throw new AbortError(`User ${userId} not found`); } // 400 - Bad request, permanent error if (response.status === 400) { const error = new Error('Invalid user ID format'); throw new AbortError(error); // Can wrap existing Error } // 5xx errors will be retried if (!response.ok) { throw new Error(`Server error: ${response.status}`); } return response.json(); }; try { const user = await pRetry(() => fetchUser('invalid-id'), {retries: 5}); console.log(user); } catch (error) { console.log(error.message); // Output: "User invalid-id not found" (no retries attempted after AbortError) } ``` -------------------------------- ### Async onFailedAttempt with Custom Delay Source: https://context7.com/sindresorhus/p-retry/llms.txt Demonstrates using an asynchronous `onFailedAttempt` callback to introduce custom delays or perform other asynchronous operations after a failed attempt, such as logging or additional waiting periods. ```javascript import pRetry from 'p-retry'; import delay from 'delay'; const fetchWithLogging = async () => { const response = await fetch('https://api.example.com/data'); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return response.json(); }; const resultWithExtraDelay = await pRetry(fetchWithLogging, { retries: 3, onFailedAttempt: async ({attemptNumber}) => { console.log(`Attempt ${attemptNumber} failed, adding extra 500ms delay`); await delay(500); } }); ``` -------------------------------- ### p-retry Function Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md The main p-retry function wraps a given function and retries it based on the provided options. ```APIDOC ## p-retry(function, options?) Wrap a function so that each call is automatically retried on failure. ### Parameters #### `function` The function to retry. It should return a Promise. #### `options` (Object) - Optional - **retries** (number) - The maximum amount of times to retry the operation. Default: `10`. - **factor** (number) - The exponential factor to use for backoff. Default: `2`. - **minTimeout** (number) - The number of milliseconds before starting the first retry. Set to `0` for immediate retries. Default: `1000`. - **maxTimeout** (number) - The maximum number of milliseconds between two retries. Default: `Infinity`. - **randomize** (boolean) - Randomizes the timeouts by multiplying with a factor between 1 and 2. Default: `false`. - **maxRetryTime** (number) - The maximum time (in milliseconds) that the retried operation is allowed to run. Default: `Infinity`. - **signal** (AbortSignal) - An AbortSignal to cancel retrying. - **unref** (boolean) - Prevents retry timeouts from keeping the process alive. Default: `false`. - **shouldConsumeRetry** (Function) - A function that decides if a failure should consume a retry. It receives an object with `error` and `retriesLeft`. If it returns `false`, the failure will not consume a retry or increment backoff values. Not called on `AbortError`. If it throws, all retries will be aborted. ### Request Example ```js import pRetry from 'p-retry'; const run = async () => { // Your async operation here }; const result = await pRetry(run, { retries: 3, minTimeout: 500, shouldConsumeRetry: ({error, retriesLeft}) => !(error instanceof RateLimitError) }); ``` ### Response #### Success Response (200) Returns the result of the successful promise. #### Response Example ```json { "data": "some result" } ``` #### Error Handling - **AbortError**: Thrown when the `signal` is aborted. - **Other Errors**: Rejects with the error from the last attempt if retries are exhausted or if `shouldConsumeRetry` throws. ``` -------------------------------- ### Selective Retry Budget with `shouldConsumeRetry` Source: https://context7.com/sindresorhus/p-retry/llms.txt Control whether a failed attempt consumes a retry from the budget using `shouldConsumeRetry`. Returning `false` for errors like `RateLimitError` prevents decrementing retries. ```javascript import pRetry from 'p-retry'; import delay from 'delay'; class RateLimitError extends Error { constructor(retryAfter) { super('Rate limited'); this.retryAfter = retryAfter; } } const fetchWithRateLimit = async () => { const response = await fetch('https://api.example.com/data'); if (response.status === 429) { const retryAfter = parseInt(response.headers.get('Retry-After') || '5', 10); throw new RateLimitError(retryAfter); } if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return response.json(); }; const result = await pRetry(fetchWithRateLimit, { retries: 3, shouldConsumeRetry: ({error}) => { // Rate limit errors don't consume retry budget if (error instanceof RateLimitError) { return false; } return true; }, onFailedAttempt: async ({error, retriesLeft}) => { if (error instanceof RateLimitError) { console.log(`Rate limited, waiting ${error.retryAfter}s (${retriesLeft} retries still available)`); await delay(error.retryAfter * 1000); } } }); ``` -------------------------------- ### Passing Arguments to Retried Function Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md How to pass arguments to the function being retried. ```APIDOC ## Tip: Passing Arguments You can pass arguments to the function being retried by wrapping it in an inline arrow function: ```js import pRetry from 'p-retry'; const run = async emoji => { // … }; // Without arguments await pRetry(run, {retries: 5}); // With arguments await pRetry(() => run('🦄'), {retries: 5}); ``` ``` -------------------------------- ### Pass Arguments to Retried Functions Source: https://context7.com/sindresorhus/p-retry/llms.txt When using `pRetry` directly with functions that require arguments, wrap the call in an arrow function to ensure arguments are passed correctly on each retry attempt. This also allows for dynamic arguments based on the attempt number. ```javascript import pRetry from 'p-retry'; const fetchUserPosts = async (userId, limit) => { const response = await fetch( `https://api.example.com/users/${userId}/posts?limit=${limit}` ); if (!response.ok) { throw new Error(`Failed to fetch posts: ${response.status}`); } return response.json(); }; // Without arguments await pRetry(fetchUserPosts, {retries: 5}); // With arguments - wrap in arrow function const posts = await pRetry( () => fetchUserPosts('user-123', 10), {retries: 5} ); console.log(posts); // Output: [{ id: 1, title: '...' }, { id: 2, title: '...' }, ...] // Dynamic arguments with attempt number const dynamicResult = await pRetry( (attemptNumber) => { console.log(`Attempt ${attemptNumber} with timeout ${attemptNumber * 5000}ms`); return fetchWithTimeout('https://api.example.com', attemptNumber * 5000); }, {retries: 3} ); ``` -------------------------------- ### makeRetriable Function Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md Wraps a function to make it automatically retriable. ```APIDOC ## makeRetriable(function, options?) Wrap a function so that each call is automatically retried on failure. ### Parameters #### `function` The function to wrap and make retriable. #### `options` (Object) - Optional Same options as the `p-retry` function. ### Request Example ```js import {makeRetriable} from 'p-retry'; const fetchWithRetry = makeRetriable(fetch, {retries: 5}); const response = await fetchWithRetry('https://sindresorhus.com/unicorn'); ``` ``` -------------------------------- ### Custom onFailedAttempt Callback Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md Implement a custom callback to log retry attempts and delays. This function is invoked after a failed attempt and before the next retry, providing detailed context about the error and retry state. ```js import pRetry from 'p-retry'; const run = async () => { const response = await fetch('https://sindresorhus.com/unicorn'); if (!response.ok) { throw new Error(response.statusText); } return response.json(); }; const result = await pRetry(run, { onFailedAttempt: ({error, attemptNumber, retriesLeft, retriesConsumed, retryDelay}) => { console.log(`Attempt ${attemptNumber} failed. Retrying in ${retryDelay}ms. ${retriesLeft} retries left.`); // 1st request => Attempt 1 failed. Retrying in 1000ms. 5 retries left. // 2nd request => Attempt 2 failed. Retrying in 2000ms. 4 retries left. // … }, retries: 5 }); console.log(result); ``` -------------------------------- ### AbortError Source: https://github.com/sindresorhus/p-retry/blob/main/readme.md Custom error to abort retrying. ```APIDOC ## AbortError(message) ## AbortError(error) Abort retrying and reject the promise. No callback functions will be called. ### Parameters - **message** (string) - An error message. - **error** (Error) - A custom error. ### Response Example ```js import pRetry, {AbortError} from 'p-retry'; try { await pRetry(run, {signal: controller.signal}); } catch (error) { if (error instanceof AbortError) { console.log('Retry aborted:', error.message); } } ``` ``` -------------------------------- ### Conditional Retries with `shouldRetry` Source: https://context7.com/sindresorhus/p-retry/llms.txt Use `shouldRetry` to define custom logic for retrying based on the error. Return `false` to abort retries for specific error types like `AuthenticationError`. ```javascript import pRetry from 'p-retry'; class RateLimitError extends Error { constructor(retryAfter) { super('Rate limited'); this.name = 'RateLimitError'; this.retryAfter = retryAfter; } } class AuthenticationError extends Error { constructor() { super('Authentication failed'); this.name = 'AuthenticationError'; } } const fetchProtectedResource = async () => { const response = await fetch('https://api.example.com/protected'); if (response.status === 429) { throw new RateLimitError(response.headers.get('Retry-After')); } if (response.status === 401) { throw new AuthenticationError(); } if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return response.json(); }; const result = await pRetry(fetchProtectedResource, { retries: 5, shouldRetry: ({error}) => { // Don't retry authentication errors - they won't succeed if (error instanceof AuthenticationError) { console.log('Auth error - not retrying'); return false; } // Retry everything else return true; } }); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.