or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# Retry

1

2

Retry provides abstraction for exponential and custom retry strategies for failed operations. It offers both operation-based retry patterns through RetryOperation objects and functional wrapper patterns that can automatically add retry logic to existing functions.

3

4

## Package Information

5

6

- **Package Name**: retry

7

- **Package Type**: npm

8

- **Language**: JavaScript

9

- **Installation**: `npm install retry`

10

- **Engine Requirements**: Node.js >= 4

11

12

## Core Imports

13

14

```javascript

15

const retry = require("retry");

16

```

17

18

Note: This package uses CommonJS exports only. ES module syntax can be used with bundlers or transpilers:

19

20

```javascript

21

import retry from "retry";

22

```

23

24

Individual function imports:

25

26

```javascript

27

const { operation, timeouts, createTimeout, wrap } = require("retry");

28

```

29

30

## Basic Usage

31

32

```javascript

33

const retry = require("retry");

34

35

function faultTolerantResolve(address, cb) {

36

const operation = retry.operation();

37

38

operation.attempt(function(currentAttempt) {

39

dns.resolve(address, function(err, addresses) {

40

if (operation.retry(err)) {

41

return;

42

}

43

44

cb(err ? operation.mainError() : null, addresses);

45

});

46

});

47

}

48

```

49

50

## Architecture

51

52

Retry is built around several key components:

53

54

- **RetryOperation Class**: Manages individual retry operation lifecycle with error collection and timer management

55

- **Exponential Backoff**: Configurable timeout calculation using exponential growth with optional randomization

56

- **Error Aggregation**: Collects and analyzes errors across retry attempts to identify most common failures

57

- **Method Wrapping**: Automatic retry logic injection into existing object methods

58

- **Timer Management**: Precise timeout control with optional unreferencing for process exit handling

59

60

## Capabilities

61

62

### Retry Operations

63

64

Create and manage retry operations with exponential backoff strategies. The core functionality for handling failed operations with configurable retry policies.

65

66

```javascript { .api }

67

/**

68

* Creates a new RetryOperation instance with computed timeouts

69

* @param {Object} [options] - Configuration options for retry behavior

70

* @param {number} [options.retries=10] - Maximum number of retry attempts

71

* @param {number} [options.factor=2] - Exponential backoff factor

72

* @param {number} [options.minTimeout=1000] - Minimum timeout in milliseconds

73

* @param {number} [options.maxTimeout=Infinity] - Maximum timeout in milliseconds

74

* @param {boolean} [options.randomize=false] - Add randomization to timeouts

75

* @param {boolean} [options.forever=false] - Whether to retry forever

76

* @param {boolean} [options.unref=false] - Whether to unref setTimeout calls

77

* @param {number} [options.maxRetryTime=Infinity] - Maximum time allowed for retries in milliseconds

78

* @returns {RetryOperation} RetryOperation instance

79

*/

80

function operation(options);

81

```

82

83

**Usage Examples:**

84

85

```javascript

86

const retry = require("retry");

87

88

// Basic retry with default settings (10 retries, exponential backoff)

89

const operation = retry.operation();

90

91

// Custom retry configuration

92

const operation = retry.operation({

93

retries: 5,

94

factor: 3,

95

minTimeout: 1 * 1000,

96

maxTimeout: 60 * 1000,

97

randomize: true,

98

});

99

100

// Retry forever with maximum retry time limit

101

const operation = retry.operation({

102

forever: true,

103

maxRetryTime: 5 * 60 * 1000, // 5 minutes max

104

});

105

```

106

107

### Timeout Generation

108

109

Generate arrays of timeout values for exponential backoff strategies. Used internally by operations but also available for custom timeout management.

110

111

```javascript { .api }

112

/**

113

* Generates array of timeout values for exponential backoff

114

* @param {Object|Array} [options] - Timeout configuration or array of timeout values

115

* @param {number} [options.retries=10] - Maximum number of retries

116

* @param {number} [options.factor=2] - Exponential backoff factor

117

* @param {number} [options.minTimeout=1000] - Minimum timeout in milliseconds

118

* @param {number} [options.maxTimeout=Infinity] - Maximum timeout in milliseconds

119

* @param {boolean} [options.randomize=false] - Add randomization to timeouts

120

* @param {boolean} [options.forever=false] - Enable infinite retries

121

* @returns {number[]} Array of timeout values in milliseconds

122

*/

123

function timeouts(options);

124

125

/**

126

* Calculates timeout value for specific attempt number

127

* @param {number} attempt - Zero-indexed attempt number

128

* @param {Object} opts - Options containing factor, minTimeout, maxTimeout, randomize

129

* @param {number} opts.factor - Exponential backoff factor

130

* @param {number} opts.minTimeout - Minimum timeout in milliseconds

131

* @param {number} opts.maxTimeout - Maximum timeout in milliseconds

132

* @param {boolean} [opts.randomize=false] - Add randomization to timeout

133

* @returns {number} Timeout value in milliseconds

134

*/

135

function createTimeout(attempt, opts);

136

```

137

138

**Usage Examples:**

139

140

```javascript

141

const retry = require("retry");

142

143

// Generate timeout array

144

const timeouts = retry.timeouts({

145

retries: 3,

146

factor: 2,

147

minTimeout: 1000,

148

maxTimeout: 5000,

149

randomize: true

150

});

151

// Result: [1000-2000, 2000-4000, 4000-5000] (randomized)

152

153

// Calculate specific timeout

154

const timeout = retry.createTimeout(2, {

155

factor: 2,

156

minTimeout: 1000,

157

maxTimeout: 10000

158

});

159

// Result: 4000 (1000 * 2^2)

160

161

// Use array of custom timeouts

162

const customTimeouts = retry.timeouts([100, 500, 1000, 2000]);

163

```

164

165

### Method Wrapping

166

167

Automatically add retry logic to existing object methods. Useful for wrapping APIs, database clients, or any object with methods that may fail.

168

169

```javascript { .api }

170

/**

171

* Wraps object methods with retry logic

172

* @param {Object} obj - Object containing methods to wrap

173

* @param {Object|Array} [options] - Retry options or method names array

174

* @param {Array} [methods] - Array of method names to wrap

175

* @returns {void} Modifies obj in place

176

*/

177

function wrap(obj, options, methods);

178

```

179

180

**Usage Examples:**

181

182

```javascript

183

const retry = require("retry");

184

const dns = require("dns");

185

186

// Wrap all functions in an object

187

retry.wrap(dns);

188

189

// Wrap specific methods

190

retry.wrap(dns, ["resolve", "lookup"]);

191

192

// Wrap with custom retry options

193

retry.wrap(dns, {

194

retries: 3,

195

factor: 2,

196

minTimeout: 1000

197

});

198

199

// Wrap specific methods with options

200

retry.wrap(dns, {

201

retries: 5,

202

maxTimeout: 10000

203

}, ["resolve"]);

204

205

// The wrapped methods now automatically retry on errors

206

dns.resolve("example.com", function(err, addresses) {

207

// This will retry up to the configured number of times

208

console.log(err, addresses);

209

});

210

```

211

212

### RetryOperation Management

213

214

Direct management of RetryOperation instances for fine-grained control over retry behavior and error handling.

215

216

```javascript { .api }

217

/**

218

* RetryOperation constructor - manages individual retry operation lifecycle

219

* @param {number[]} timeouts - Array of timeout values in milliseconds

220

* @param {Object|boolean} [options] - Configuration options

221

* @param {boolean} [options.forever=false] - Whether to retry forever

222

* @param {boolean} [options.unref=false] - Whether to unref setTimeout calls

223

* @param {number} [options.maxRetryTime=Infinity] - Maximum time allowed for retries

224

*/

225

function RetryOperation(timeouts, options);

226

227

/**

228

* Executes function with retry capability

229

* @param {Function} fn - Function to execute, receives currentAttempt as parameter

230

* @param {Object} [timeoutOps] - Timeout configuration

231

* @param {number} [timeoutOps.timeout] - Operation timeout in milliseconds

232

* @param {Function} [timeoutOps.cb] - Timeout callback function

233

* @returns {void}

234

*/

235

RetryOperation.prototype.attempt = function(fn, timeoutOps);

236

237

/**

238

* Determines if operation should be retried based on error

239

* @param {Error|null} err - Error from operation attempt

240

* @returns {boolean} true if operation will be retried, false otherwise

241

*/

242

RetryOperation.prototype.retry = function(err);

243

244

/**

245

* Stops retry operation and clears timers

246

* @returns {void}

247

*/

248

RetryOperation.prototype.stop = function();

249

250

/**

251

* Resets operation to initial state for reuse

252

* @returns {void}

253

*/

254

RetryOperation.prototype.reset = function();

255

256

/**

257

* Returns array of all errors encountered during retries

258

* @returns {Error[]} Array of Error objects in chronological order

259

*/

260

RetryOperation.prototype.errors = function();

261

262

/**

263

* Returns current attempt count

264

* @returns {number} Number representing attempt count

265

*/

266

RetryOperation.prototype.attempts = function();

267

268

/**

269

* Returns most frequently occurring error

270

* @returns {Error|null} Error object or null if no errors

271

*/

272

RetryOperation.prototype.mainError = function();

273

274

/**

275

* @deprecated Use attempt() instead

276

* Deprecated alias for attempt()

277

* @param {Function} fn - Function to execute

278

* @returns {void}

279

*/

280

RetryOperation.prototype.try = function(fn);

281

282

/**

283

* @deprecated Use attempt() instead

284

* Deprecated alias for attempt()

285

* @param {Function} fn - Function to execute

286

* @returns {void}

287

*/

288

RetryOperation.prototype.start = function(fn);

289

```

290

291

**Usage Examples:**

292

293

```javascript

294

const retry = require("retry");

295

296

// Direct RetryOperation usage

297

const timeouts = retry.timeouts({ retries: 3 });

298

const operation = new retry.RetryOperation(timeouts);

299

300

operation.attempt(function(currentAttempt) {

301

console.log(`Attempt ${currentAttempt}`);

302

303

asyncOperation(function(err, result) {

304

if (err && err.message === 'FATAL_ERROR') {

305

// Stop retrying on fatal errors

306

operation.stop();

307

return callback(err);

308

}

309

310

if (operation.retry(err)) {

311

return; // Will retry

312

}

313

314

// Final result (success or max retries reached)

315

if (err) {

316

console.log('All errors:', operation.errors());

317

console.log('Main error:', operation.mainError());

318

console.log('Total attempts:', operation.attempts());

319

}

320

321

callback(operation.mainError(), result);

322

});

323

});

324

325

// Reset and reuse operation

326

operation.reset();

327

operation.attempt(/* ... */);

328

```

329

330

## Types

331

332

```javascript { .api }

333

/**

334

* Configuration options for retry operations

335

* @typedef {Object} RetryOptions

336

* @property {number} [retries=10] - Maximum number of retry attempts

337

* @property {number} [factor=2] - Exponential backoff factor

338

* @property {number} [minTimeout=1000] - Minimum timeout in milliseconds

339

* @property {number} [maxTimeout=Infinity] - Maximum timeout in milliseconds

340

* @property {boolean} [randomize=false] - Add randomization to timeouts

341

* @property {boolean} [forever=false] - Whether to retry forever

342

* @property {boolean} [unref=false] - Whether to unref setTimeout calls

343

* @property {number} [maxRetryTime=Infinity] - Maximum time allowed for retries in milliseconds

344

*/

345

346

/**

347

* Timeout operation configuration

348

* @typedef {Object} TimeoutOps

349

* @property {number} timeout - Operation timeout in milliseconds

350

* @property {Function} cb - Timeout callback function

351

*/

352

```

353

354

## Error Handling

355

356

The retry library provides comprehensive error handling and analysis:

357

358

### Error Collection

359

- All retry attempts collect errors in chronological order via `errors()`

360

- `mainError()` returns the most frequently occurring error based on error message

361

- Error aggregation supports detailed failure analysis

362

363

### Special Error Behaviors

364

- **Timeout errors**: Automatically added when `maxRetryTime` is exceeded

365

- **Fatal error handling**: Use `operation.stop()` to abort retries for unrecoverable errors

366

- **Forever mode**: When `forever: true`, only keeps the last error to prevent memory leaks

367

368

### Timeout Formula

369

The timeout calculation uses the following formula:

370

```

371

timeout = Math.min(random * Math.max(minTimeout, 1) * Math.pow(factor, attempt), maxTimeout)

372

```

373

Where `random` is 1 or a value between 1-2 if `randomize` is enabled. The `Math.max(minTimeout, 1)` ensures a minimum timeout of at least 1 millisecond.

374

375

## Common Patterns

376

377

### DNS Resolution with Retry

378

```javascript

379

const dns = require("dns");

380

const retry = require("retry");

381

382

function faultTolerantResolve(address, cb) {

383

const operation = retry.operation({

384

retries: 2,

385

factor: 2,

386

minTimeout: 1 * 1000,

387

maxTimeout: 2 * 1000,

388

randomize: true

389

});

390

391

operation.attempt(function(currentAttempt) {

392

dns.resolve(address, function(err, addresses) {

393

if (operation.retry(err)) {

394

return;

395

}

396

397

cb(operation.mainError(), operation.errors(), addresses);

398

});

399

});

400

}

401

```

402

403

### API Client with Fatal Error Handling

404

```javascript

405

function apiCall(endpoint, data, callback) {

406

const operation = retry.operation({ retries: 3 });

407

408

operation.attempt(function(currentAttempt) {

409

httpRequest(endpoint, data, function(err, response) {

410

if (err && err.statusCode === 401) {

411

// Don't retry authentication errors

412

operation.stop();

413

return callback(err);

414

}

415

416

if (operation.retry(err)) {

417

return;

418

}

419

420

callback(operation.mainError(), response);

421

});

422

});

423

}

424

```

425

426

### Database Connection with Wrapping

427

```javascript

428

const retry = require("retry");

429

430

// Wrap database client methods

431

retry.wrap(dbClient, {

432

retries: 5,

433

factor: 1.5,

434

minTimeout: 500,

435

maxTimeout: 10000

436

}, ["query", "connect"]);

437

438

// Now database operations automatically retry

439

dbClient.query("SELECT * FROM users", function(err, results) {

440

// This query will retry up to 5 times on failure

441

console.log(err, results);

442

});

443

```