{"id":13448613,"url":"https://github.com/wsmd/reattempt","last_synced_at":"2025-04-05T09:07:49.568Z","repository":{"id":34699169,"uuid":"181360063","full_name":"wsmd/reattempt","owner":"wsmd","description":"🤞 Give your functions another chance","archived":false,"fork":false,"pushed_at":"2023-01-07T04:44:41.000Z","size":2161,"stargazers_count":572,"open_issues_count":19,"forks_count":11,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-12-18T06:18:47.582Z","etag":null,"topics":["attempt","error-handling","errors","functions","javascript","retry","try-catch"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/wsmd.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":"2019-04-14T19:41:05.000Z","updated_at":"2024-11-15T16:22:24.000Z","dependencies_parsed_at":"2023-01-15T08:45:40.772Z","dependency_job_id":null,"html_url":"https://github.com/wsmd/reattempt","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wsmd%2Freattempt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wsmd%2Freattempt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wsmd%2Freattempt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wsmd%2Freattempt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wsmd","download_url":"https://codeload.github.com/wsmd/reattempt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247312078,"owners_count":20918344,"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":["attempt","error-handling","errors","functions","javascript","retry","try-catch"],"created_at":"2024-07-31T05:01:50.565Z","updated_at":"2025-04-05T09:07:49.159Z","avatar_url":"https://github.com/wsmd.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n\u003cimg width=\"144\" src=\"https://user-images.githubusercontent.com/2100222/56097756-9520c880-5ec6-11e9-9e77-9a2b5339fbf8.png\"\u003e\n\nreattempt\n\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/reattempt\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/reattempt.svg\" alt=\"Current Release\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://travis-ci.org/wsmd/reattempt\"\u003e\n    \u003cimg src=\"https://travis-ci.org/wsmd/reattempt.svg?branch=master\" alt=\"CI Build\"\u003e\n  \u003c/a\u003e\n  \u003ca href='https://coveralls.io/github/wsmd/reattempt?branch=master'\u003e\n    \u003cimg src='https://coveralls.io/repos/github/wsmd/reattempt/badge.svg?branch=master' alt='Coverage Status' /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/wsmd/reattempt/blob/master/LICENSE\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/license/wsmd/reattempt.svg\" alt=\"Licence\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003e `reattempt` is a modern JavaScript library for the browser and Node.js that lets you retry asynchronous functions when they fail - because some functions deserve a second chance, or a third or maybe even several dozen or so.\n\n\u003cdetails\u003e\n\u003csummary\u003e📖 Table of Contents\u003c/summary\u003e\n\u003cp\u003e\n\n- [Highlights](#highlights)\n- [Getting Started](#getting-started)\n- [Usage](#usage)\n  - [Asynchronous Promise-Based Functions](#asynchronous-promise-based-functions)\n  - [Node.js Error-First Callbacks](#nodejs-error-first-callbacks)\n  - [Custom Interface Functions](#custom-interface-functions)\n  - [Intercepting Attempts](#intercepting-attempts)\n  - [Working with TypeScript](#working-with-typescript)\n    - [Reattempt As A Decorator](#reattempt-as-a-decorator)\n    - [Type Safe Callbacks](#type-safe-callbacks)\n- [API](#api)\n  - [Methods](#methods)\n    - [`run(options: Options, callback: Callback): Promise`](#runoptions-options-callback-callback-promise)\n  - [Reattempt Options](#reattempt-options)\n    - [`times: number`](#times-number)\n    - [`delay?: number`](#delay-number)\n    - [`onError?(error, done, abort): void`](#onerrorerror-done-abort-void)\n  - [Reattempt Callback](#reattempt-callback)\n  - [The `done` Callback](#the-done-callback)\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n## Highlights\n\n- 🚀 Very lightweight: ~550 bytes minified+gzipped\n- ⚡️ Modern asynchronous JavaScript support with Promises and Async/Await\n- 💪 Flexible API that covers many cases\n- 🛠 Targeted for both the browser and Node.js\n- ⛑ Type-safety with TypeScript and a built-in decorator\n\n## Getting Started\n\nTo get started, add `reattempt` to your project:\n\n```\nnpm i --save-dev reattempt\n```\n\n## Usage\n\n### Asynchronous Promise-Based Functions\n\nWhen an `async` function (or a function that returns a `Promise`) is passed to `Reattempt.run`, the function will be called immediately. If the functions reject with an error, `Reattempt.run` will retry calling that function. The function will be retried until it resolves, or until the maximum retries count is reached, whichever comes first.\n\n```js\nimport Reattempt from 'reattempt';\n\nasync function doSomethingAsync() {\n  // doing async operation that may throw\n  return result;\n}\n\nasync function main() {\n  try {\n    const result = await Reattempt.run({ times: 3 }, doSomethingAsync);\n  } catch (error) {\n    // an error is thrown if the function rejects with an error after\n    // exhausting all attempts\n  }\n}\n```\n\n### Node.js Error-First Callbacks\n\nReattempt also works with functions following the _error-first callbacks_ pattern. When working with these functions, instead of passing an `async` or `Promise` based function, pass a function with a single argument called `done`. Use this argument as the error-first callback of your function.\n\nThe function will be retried until it returns a value without an error, or until the maximum retries count is reached, whichever comes first.\n\n```js\nimport fs from 'fs';\nimport Reattempt from 'reattempt';\n\nasync function main() {\n  try {\n    const data = await Reattempt.run({ times: 3 }, done =\u003e {\n      fs.readFile('./path/to/file', 'utf8', done);\n    });\n  } catch (error) {\n    // an error is thrown if the function rejects with an error after\n    // exhausting all attempts\n  }\n}\n```\n\n### Custom Interface Functions\n\nSimilar to working with _[Node.js Error-First Callbacks](#nodejs-error-first-callbacks)_, the `done` callback can be used to reattempt any asynchronous function with custom callback interface. For example, some APIs expects an `onSuccess` and `onError` callbacks.\n\nThe properties `done.resolve` and `done.reject` can be used to hook into any custom interface and perform reattempts as needed.\n\n```ts\nfunction doSomething(onSuccess, onError) {\n  // some async operations\n}\n\nasync function main() {\n  try {\n    const data = await Reattempt.run({ times: 3 }, done =\u003e {\n      doSomething(done.resolve, done.reject);\n    });\n  } catch (error) {\n    // an error is thrown if the function rejects with an error after\n    // exhausting all attempts\n  }\n}\n```\n\n### Intercepting Attempts\n\nThere are cases when you need to intercept an attempt call. It's possible to control the reattempt flow, by providing the `onError` option. This option allows you to intercept each attempt and control the reattempt flow.\n\n\u003c!-- prettier-ignore --\u003e\n```js\nimport Reattempt from 'reattempt';\n\nasync function doSomething() {\n  // some async operations\n}\n\nfunction handleError(\n  error /* the error object that the function rejected with */,\n  done  /* resolves the function call with a custom value */,\n  abort /* bail out of remaining attempts and rejects with current error */,\n) {\n  if (shouldAbortRemainingAttempts) {\n    abort();\n  } else if (shouldSkipAttemptsAndResolve) {\n    done(defaultValue);\n  }\n}\n\nasync function main() {\n  try {\n    const result = await Reattempt.run(\n      { times: 10, onError: handleError },\n      doSomething,\n    );\n  } catch (error) {\n    // ...\n  }\n}\n```\n\n### Working with TypeScript\n\n#### Reattempt As A Decorator\n\nReattempt also comes as a decorator that can be imported from `reattempt/decorator`.\n\n```ts\nimport Reattempt from 'reattempt/decorator';\n\nclass Group {\n  @Reattempt({ times: 3, delay: 5000 })\n  private async getUserIds() {\n    const user = await fakeAPI.getUsers(this.id); // could throw!\n    return users.map(user =\u003e user.id);\n  }\n\n  public async doSomething() {\n    try {\n      const result = await this.getUserIds();\n    } catch (error) {\n      // Only throws after failing 3 attempts with 5 seconds in between\n    }\n  }\n}\n```\n\n#### Type Safe Callbacks\n\nReattempt can infer types of async and Promise-based functions automatically.\n\nHowever, when working with error-first callbacks, you can enforce type safety by passing a type argument informing Reattempt about the list of success arguments the original function could potentially provide.\n\n```ts\nReattempt\n  .run\u003c[string, string]\u003e({ times: 3 }, done =\u003e {\n    childProcess.exec('cat *.md | wc -w', attempt);\n  })\n  // resolves with an array of success type-safe arguments\n  .then(([stdout, stderr]) =\u003e stdout.trim())\n  .catch(error =\u003e /* ... */);\n```\n\n## API\n\n### Methods\n\n#### `run(options: Options, callback: Callback): Promise`\n\nRuns and reattempt the provided callback. If the callback fails, it will be reattempted until it resolves, or until the maximum retries count `options.times` is reached, whichever comes first.\n\nReturns a `Promise` that resolves with the result of the provided function, and rejects with the same error it could reject with.\n\n### Reattempt Options\n\nAll Reattempt methods accept an options object as the first argument with the following properties:\n\n#### `times: number`\n\nThe number of times a function can be reattempted.\n\nIf this property is not provided Reattempt will perform the provided function once without any additional reattempts on failure.\n\n#### `delay?: number`\n\nThe duration in milliseconds between each attempt. Defaults to `0`.\n\nIf this property is not provided Reattempt will perform a reattempt as soon as the function fails.\n\n#### `onError?(error, done, abort): void`\n\nA callback that fires on each attempt after receiving an error. It allows you to intercept an attempt and gives you access to the error object. It passes the following parameters:\n\n- `error: any`: the error that the function rejected with\n- `done(value: any): void`: a function that allows you to skip remaining reattempts and resolve the attempted function with the value provided.\n- `abort(): void`: a function allowing you to bail out of remaining attempts and rejects the attempted function immediately.\n\n### Reattempt Callback\n\nAll Reattempt methods take a function as the second argument.\n\nThis function will be reattempted on failure and can be one of three forms:\n\n- An `async` function.\n\n```js\nReattempt.run({ times: 2 }, async () =\u003e {\n  // ...\n});\n```\n\n- A function that returns a `Promise`\n\n```js\nReattempt.run({ times: 2 }, () =\u003e {\n  return new Promise((resolve, reject) =\u003e {\n    //...\n  });\n});\n```\n\n- A non-`async`, non-`Promise` function that wraps functions with error-first-callbacks\n\n```js\nReattempt.run({ times: 2 }, done =\u003e {\n  fs.readFile('path/to/file', 'utf-8', done);\n});\n```\n\n### The `done` Callback\n\nIf you are reattempting a non-`async` function (or a function that does not return a `Promise`), pass a callback function with one argument `done`.\n\nThis argument controls the reattempt flow and can be used in one of two ways:\n\n- As an error-first callback that you can pass to any function such as most Node.js APIs\n- As a hook to custom interfaces that expects success and error callbacks by utilizing the two properties `done.resolve` and `done.reject`.\n\n# License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwsmd%2Freattempt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwsmd%2Freattempt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwsmd%2Freattempt/lists"}