@humanwhocodes/retry
Advanced tools
Comparing version 0.2.4 to 0.3.0
@@ -19,7 +19,11 @@ /** | ||
* @param {Function} fn The function to call. | ||
* @param {object} [options] The options for the job. | ||
* @param {AbortSignal} [options.signal] The AbortSignal to monitor for cancellation. | ||
* @returns {Promise<any>} A promise that resolves when the queue is | ||
* processed. | ||
*/ | ||
retry(fn: Function): Promise<any>; | ||
retry(fn: Function, { signal }?: { | ||
signal?: AbortSignal | undefined; | ||
} | undefined): Promise<any>; | ||
#private; | ||
} |
@@ -0,1 +1,2 @@ | ||
/// <reference types="./retrier.d.ts" /> | ||
/** | ||
@@ -104,2 +105,8 @@ * @fileoverview A utility for retrying failed async method calls. | ||
/** | ||
* The AbortSignal to monitor for cancellation. | ||
* @type {AbortSignal|undefined} | ||
*/ | ||
signal; | ||
/** | ||
* Creates a new instance. | ||
@@ -110,4 +117,5 @@ * @param {Function} fn The function to call. | ||
* @param {Function} reject The reject function for the promise. | ||
* @param {AbortSignal|undefined} signal The AbortSignal to monitor for cancellation. | ||
*/ | ||
constructor(fn, error, resolve, reject) { | ||
constructor(fn, error, resolve, reject, signal) { | ||
this.fn = fn; | ||
@@ -119,2 +127,3 @@ this.error = error; | ||
this.reject = reject; | ||
this.signal = signal; | ||
} | ||
@@ -183,7 +192,11 @@ | ||
* @param {Function} fn The function to call. | ||
* @param {object} [options] The options for the job. | ||
* @param {AbortSignal} [options.signal] The AbortSignal to monitor for cancellation. | ||
* @returns {Promise<any>} A promise that resolves when the queue is | ||
* processed. | ||
*/ | ||
retry(fn) { | ||
retry(fn, { signal } = {}) { | ||
signal?.throwIfAborted(); | ||
let result; | ||
@@ -210,3 +223,8 @@ | ||
return new Promise((resolve, reject) => { | ||
this.#queue.push(new RetryTask(fn, error, resolve, reject)); | ||
this.#queue.push(new RetryTask(fn, error, resolve, reject, signal)); | ||
signal?.addEventListener("abort", () => { | ||
reject(signal.reason); | ||
}); | ||
this.#processQueue(); | ||
@@ -213,0 +231,0 @@ }); |
@@ -1,1 +0,1 @@ | ||
class RetryTask{fn;error;timestamp=Date.now();lastAttempt=this.timestamp;resolve;reject;constructor(t,e,r,s){this.fn=t,this.error=e,this.timestamp=Date.now(),this.lastAttempt=Date.now(),this.resolve=r,this.reject=s}}class Retrier{#t=[];#e;#r;#s;#i;constructor(t,{timeout:e=6e4,maxDelay:r=100}={}){if("function"!=typeof t)throw new Error("Missing function to check errors");this.#i=t,this.#e=e,this.#r=r}retry(t){let e;try{e=t()}catch(t){return Promise.reject(new Error(`Synchronous error: ${t.message}`,{cause:t}))}return e&&"function"==typeof e.then?Promise.resolve(e).catch((e=>{if(!this.#i(e))throw e;return new Promise(((r,s)=>{this.#t.push(new RetryTask(t,e,r,s)),this.#o()}))})):Promise.reject(new Error("Result is not a promise."))}#o(){clearTimeout(this.#s),this.#s=void 0;const t=this.#t.shift();if(t){if(function(t,e){return Date.now()-t.timestamp>e}(t,this.#e))return t.reject(t.error),void this.#o();if(!function(t,e){const r=Date.now()-t.lastAttempt,s=Math.max(t.lastAttempt-t.timestamp,1);return r>=Math.min(1.2*s,e)}(t,this.#r))return this.#t.unshift(t),void(this.#s=setTimeout((()=>this.#o()),0));t.lastAttempt=Date.now(),Promise.resolve(t.fn()).then((e=>t.resolve(e))).catch((e=>{this.#i(e)?(t.lastAttempt=Date.now(),this.#t.push(t)):t.reject(e)})).finally((()=>this.#o()))}}}export{Retrier}; | ||
class RetryTask{fn;error;timestamp=Date.now();lastAttempt=this.timestamp;resolve;reject;signal;constructor(t,e,r,s,i){this.fn=t,this.error=e,this.timestamp=Date.now(),this.lastAttempt=Date.now(),this.resolve=r,this.reject=s,this.signal=i}}class Retrier{#t=[];#e;#r;#s;#i;constructor(t,{timeout:e=6e4,maxDelay:r=100}={}){if("function"!=typeof t)throw new Error("Missing function to check errors");this.#i=t,this.#e=e,this.#r=r}retry(t,{signal:e}={}){let r;e?.throwIfAborted();try{r=t()}catch(t){return Promise.reject(new Error(`Synchronous error: ${t.message}`,{cause:t}))}return r&&"function"==typeof r.then?Promise.resolve(r).catch((r=>{if(!this.#i(r))throw r;return new Promise(((s,i)=>{this.#t.push(new RetryTask(t,r,s,i,e)),e?.addEventListener("abort",(()=>{i(e.reason)})),this.#o()}))})):Promise.reject(new Error("Result is not a promise."))}#o(){clearTimeout(this.#s),this.#s=void 0;const t=this.#t.shift();if(t){if(function(t,e){return Date.now()-t.timestamp>e}(t,this.#e))return t.reject(t.error),void this.#o();if(!function(t,e){const r=Date.now()-t.lastAttempt,s=Math.max(t.lastAttempt-t.timestamp,1);return r>=Math.min(1.2*s,e)}(t,this.#r))return this.#t.unshift(t),void(this.#s=setTimeout((()=>this.#o()),0));t.lastAttempt=Date.now(),Promise.resolve(t.fn()).then((e=>t.resolve(e))).catch((e=>{this.#i(e)?(t.lastAttempt=Date.now(),this.#t.push(t)):t.reject(e)})).finally((()=>this.#o()))}}}export{Retrier}; |
{ | ||
"name": "@humanwhocodes/retry", | ||
"version": "0.2.4", | ||
"version": "0.3.0", | ||
"description": "A utility to retry failed async methods.", | ||
@@ -11,3 +11,3 @@ "type": "module", | ||
"require": { | ||
"types": "./dist/retrier.d.ts", | ||
"types": "./dist/retrier.d.cts", | ||
"default": "./dist/retrier.cjs" | ||
@@ -42,3 +42,5 @@ }, | ||
"scripts": { | ||
"build": "rollup -c && tsc", | ||
"build:cts-types": "node -e \"fs.copyFileSync('dist/retrier.d.ts', 'dist/retrier.d.cts')\"", | ||
"build:prepend-type-ref": "node tools/prepend-type-ref.js dist/retrier.js", | ||
"build": "rollup -c && tsc && npm run build:prepend-type-ref && npm run build:cts-types", | ||
"prepare": "npm run build", | ||
@@ -68,3 +70,3 @@ "lint": "eslint src/ tests/", | ||
"@types/mocha": "^10.0.3", | ||
"@types/node": "20.11.14", | ||
"@types/node": "20.12.6", | ||
"eslint": "^8.21.0", | ||
@@ -74,5 +76,5 @@ "lint-staged": "15.2.1", | ||
"rollup": "3.29.4", | ||
"typescript": "5.4.2", | ||
"typescript": "5.4.4", | ||
"yorkie": "2.0.0" | ||
} | ||
} |
@@ -106,2 +106,18 @@ # Retry utility | ||
You can also pass an `AbortSignal` to cancel a retry: | ||
```js | ||
import fs from "fs/promises"; | ||
const controller = new AbortController(); | ||
const retrier = new Retrier(error => { | ||
return error.code === "ENFILE" || error.code === "EMFILE"; | ||
}); | ||
const text = await retrier.retry( | ||
() => fs.readFile("README.md", "utf8"), | ||
{ signal: controller.signal } | ||
); | ||
``` | ||
## Developer Setup | ||
@@ -108,0 +124,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
44273
9
744
139
12
2
1
12