{"id":16758413,"url":"https://github.com/kessler/exponential-backoff","last_synced_at":"2025-04-10T17:14:01.295Z","repository":{"id":39620037,"uuid":"96575230","full_name":"kessler/exponential-backoff","owner":"kessler","description":"Opinionated exponential backoff retry driver","archived":false,"fork":false,"pushed_at":"2020-11-19T03:09:25.000Z","size":23,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-04T03:31:51.115Z","etag":null,"topics":["exponential-backoff","nodejs","nodejs-modules","npm-package"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kessler.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-07-07T20:43:41.000Z","updated_at":"2022-06-24T16:06:25.000Z","dependencies_parsed_at":"2022-09-19T16:00:46.936Z","dependency_job_id":null,"html_url":"https://github.com/kessler/exponential-backoff","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kessler%2Fexponential-backoff","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kessler%2Fexponential-backoff/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kessler%2Fexponential-backoff/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kessler%2Fexponential-backoff/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kessler","download_url":"https://codeload.github.com/kessler/exponential-backoff/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247817883,"owners_count":21001275,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["exponential-backoff","nodejs","nodejs-modules","npm-package"],"created_at":"2024-10-13T04:05:12.712Z","updated_at":"2025-04-10T17:14:01.275Z","avatar_url":"https://github.com/kessler.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## @kessler/exponential-backoff\r\n\r\n**Opinionated modern exponential backoff retry driver**\r\n\r\n[![npm status](http://img.shields.io/npm/v/@kessler/exponential-backoff.svg?style=flat-square)](https://www.npmjs.org/package/@kessler/exponential-backoff) [![Travis build status](https://img.shields.io/travis/kessler/exponential-backoff.svg?style=flat-square\u0026label=travis)](http://travis-ci.org/kessler/exponential-backoff) [![Dependency status](https://img.shields.io/david/kessler/@kessler/exponential-backoff.svg?style=flat-square)](https://david-dm.org/kessler/@kessler/exponential-backoff)\r\n\r\nAs of version `3.x` callback support is dropped.\r\n\r\n### install\r\n\r\n```\r\nnpm i -S @kessler/exponential-backoff\r\n```\r\n\r\n### simplest example\r\n\r\n```js\r\nconst backoff = require('@kessler/exponential-backoff')\r\n\r\nasync function main() {\r\n  \r\n  // if an error is thrown then work will be retried\r\n  // with an appropriate delay\r\n  // after `maxAttempts` is exceeded \r\n  // an 'operation failed, exceeded maximum attempts' Error\r\n  // is thrown and the retry process stops\r\n  const work = () =\u003e httpRequest('http://example.com')\r\n  const response = await backoff(work)\r\n}\r\n\r\n```\r\n\r\n### changing the retry behavior\r\n\r\n```js\r\nconst backoff = require('@kessler/exponential-backoff')\r\n\r\nasync function main() {\r\n  \r\n  const work = () =\u003e httpRequest('http://example.com')\r\n  // more details about these options below\r\n  const response = await backoff(work, {\r\n    maxAttempts: 100,\r\n    maxExponent: 10\r\n  })\r\n}\r\n```\r\n#### configuration options\r\n\r\n- **maxAttempts** (Default 100) - maximum number of attempts before giving up. Meaning, if the 100th attempt fails an error will be thrown.\r\n- **throwMaxAttemptsError** (Default true) - if set to false, no error will be thrown when maxAttempts is exceeded\r\n- **delayInterval** (Default 100) - minimum delay unit, random(0, Math.pow(base, attemptNumber or maxAttempts)) * delayInterval = next delay\r\n- **base** (Default 2) - base exponent for backoff algorithm\r\n- **maxExponent** (Default 10) - in exponential backoff the number of attempts is used as the exponent, this is the maximum value that can be used even if retries exceed this value\r\n- **unrefTimer** (Default false) - retry delay is achieved using setTimeout(). by default it will be unrefed, so the process will  not wait for these timers to finish\r\n\r\n### iteration API\r\n\r\nYou can also _iterate_ over the attempts for better insight into and control over the process.\r\n \r\n```js\r\nconst backoff = require('@kessler/exponential-backoff')\r\n\r\nasync function main() {\r\n  \r\n  const work = () =\u003e httpRequest('http://example.com')\r\n  const iterator = backoff.iterator(work /*, { you can provide options here } */)\r\n  \r\n  for await (let attempt of iterator) {\r\n    console.log(`this is attempt #${attempt}`)\r\n    if (attempt \u003e 0) {\r\n      console.log(iterator.lastError)\r\n    }\r\n\r\n    if (attempt \u003e 2) {\r\n      break;\r\n    }\r\n  }\r\n\r\n  // proceed from attempt #2 until maxAttempts\r\n  for await (let attempt of iterator) {\r\n\r\n  }\r\n\r\n  console.log(iterator.result)\r\n}\r\n\r\n```\r\n\r\n### optimized version\r\n\r\nThe startup code in `backoff()` has a cost. You can see the code in [bench.js](bench.js). In situations where you need a performence optimization, use the cached version (but remember: _preoptimization is the root of all evil!_):\r\n\r\n```js\r\nconst backoff = require('@kessler/exponential-backoff')\r\n\r\nasync function main() {\r\n  \r\n  const retry = backoff.cached(/* options */)\r\n  const work = () =\u003e httpRequest('http://example.com')\r\n  for (let i = 0; i \u003c 1000; i++) {\r\n    const response = await retry(work)\r\n  }\r\n}\r\n\r\n```\r\n\r\nalso cached iterator:\r\n```js\r\nconst backoff = require('@kessler/exponential-backoff')\r\n\r\nasync function main() {\r\n  \r\n  const createIterator = backoff.cachedIterator(/* options */)\r\n  const work = () =\u003e httpRequest('http://example.com')\r\n  for (let i = 0; i \u003c 1000; i++) {\r\n    const iterator = createIterator(work)\r\n    for await (const attempt of iterator) {}\r\n  }\r\n}\r\n\r\n```\r\n\r\n### infinite max attempts\r\nSpecifiying maxAttempts = Infinity can be handy in situations where you want to retry forever or control the maximum attempts dynamically.\r\n\r\nThis, however, will never through a `operation failed, exceeded maximum attempts` error and implicitly ignores `throwMaxAttemptsError` flag\r\n\r\n```js\r\nconst backoff = require('@kessler/exponential-backoff')\r\n\r\nasync function main() {\r\n  \r\n  const work = attempt =\u003e {\r\n    if (attempt \u003e computeMaxAttemptSomehow()) {\r\n      return\r\n    }\r\n\r\n    return httpRequest('http://example.com')\r\n  }\r\n  const response = await backoff(work, { maxAttempts: Infinity })\r\n}\r\n\r\n```\r\n\r\n### debug log\r\n\r\nThis module uses [debug](https://github.com/visionmedia/debug) module. set `DEBUG=@kessler/exponential-backoff` to show debug messages.\r\n\r\n### other stuff\r\n\r\nThis module is based on the [wikipedia article for exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff)\r\n\r\nThe use of the word _attempt_ is used in the code instead of _retry_ mostly because of the wikipedia article.\r\n\r\n## license\r\n\r\n[MIT](http://opensource.org/licenses/MIT) © Yaniv Kessler\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkessler%2Fexponential-backoff","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkessler%2Fexponential-backoff","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkessler%2Fexponential-backoff/lists"}