https://github.com/matthewbub/fetch-with-retry
A promise-based fetch with retry, heavily based on p-retry and is-network-error. This is a consolidated version of the two packages with type checking and a few other changes.
https://github.com/matthewbub/fetch-with-retry
Last synced: 11 months ago
JSON representation
A promise-based fetch with retry, heavily based on p-retry and is-network-error. This is a consolidated version of the two packages with type checking and a few other changes.
- Host: GitHub
- URL: https://github.com/matthewbub/fetch-with-retry
- Owner: matthewbub
- Created: 2025-07-07T05:52:54.000Z (12 months ago)
- Default Branch: main
- Last Pushed: 2025-07-07T05:54:34.000Z (12 months ago)
- Last Synced: 2025-08-03T16:58:20.229Z (11 months ago)
- Language: TypeScript
- Size: 30.3 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: readme.md
Awesome Lists containing this project
README
# fetch-with-retry
A promise-based fetch with retry, heavily based on [p-retry](https://github.com/sindresorhus/p-retry) and i[s-network-error](https://github.com/sindresorhus/is-network-error). This is a consolidated version of the two packages with type checking and a few other changes.
## Features
- **Exponential backoff** with configurable factor and randomization
- **Network error detection** across different browsers and environments
- **Abort signal support** for cancelling retry operations
- **Time-based limits** with `maxRetryTime` option
- **Custom retry logic** with `shouldRetry` callback
- **TypeScript support** with full type definitions
- **Zero dependencies** - consolidated implementation
## Usage
### Basic Example
```typescript
import { fetchWithRetry } from "./fetch-with-retry";
const result = await fetchWithRetry(
async (attemptNumber) => {
console.log(`Attempt ${attemptNumber}`);
return fetch("https://api.example.com/data");
},
{
retries: 3,
minTimeout: 1000,
maxTimeout: 5000,
factor: 2,
}
);
```
### Advanced Configuration
```typescript
import { fetchWithRetry } from "./fetch-with-retry";
const result = await fetchWithRetry(
async (attemptNumber) => {
const response = await fetch("https://api.example.com/data");
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response.json();
},
{
retries: 5,
factor: 2,
minTimeout: 1000,
maxTimeout: 30000,
randomize: true,
maxRetryTime: 60000, // Stop after 1 minute total
onFailedAttempt: async ({ error, attemptNumber, retriesLeft }) => {
console.log(`Attempt ${attemptNumber} failed: ${error.message}`);
console.log(`${retriesLeft} retries left`);
},
shouldRetry: async ({ error, attemptNumber }) => {
// Don't retry on 4xx errors (client errors)
if (error.message.includes("HTTP 4")) {
return false;
}
return true;
},
signal: AbortSignal.timeout(120000), // Overall timeout
unref: true, // Don't keep Node.js process alive
}
);
```
## API
### `fetchWithRetry(input, options)`
#### Parameters
- **`input`** `(attemptNumber: number) => Promise` - Function that returns a promise to retry
- **`options`** `RetryOptions` - Configuration options
#### RetryOptions
| Option | Type | Default | Description |
| ----------------- | ------------- | ----------------------------- | --------------------------------------- |
| `retries` | `number` | `10` | Number of retry attempts |
| `factor` | `number` | `2` | Exponential backoff factor |
| `minTimeout` | `number` | `1000` | Minimum delay between retries (ms) |
| `maxTimeout` | `number` | `Infinity` | Maximum delay between retries (ms) |
| `randomize` | `boolean` | `false` | Add randomization to delays (1.0-2.0x) |
| `maxRetryTime` | `number` | `Infinity` | Maximum total time for all retries (ms) |
| `onFailedAttempt` | `function` | `() => Promise.resolve()` | Callback on each failed attempt |
| `shouldRetry` | `function` | `() => Promise.resolve(true)` | Custom retry logic |
| `signal` | `AbortSignal` | `undefined` | Abort signal for cancellation |
| `unref` | `boolean` | `false` | Don't keep Node.js process alive |
#### Callback Context
Both `onFailedAttempt` and `shouldRetry` receive a context object:
```typescript
{
error: Error; // The error that occurred
attemptNumber: number; // Current attempt (1-based)
retriesLeft: number; // Remaining retry attempts
}
```
## Development
### Scripts
- `pnpm run test` - Run tests with Vitest
- `pnpm run build` - Build TypeScript to JavaScript
### Testing
The project uses Vitest for testing. Tests cover network error detection across different browser environments and error conditions.
```bash
pnpm test
```
## License
MIT