@creejs/commons-retrier
Version:
Common Utils About Task Retrying
1 lines • 106 kB
Source Map (JSON)
{"version":3,"file":"index-dev.cjs","sources":["../../../lang/dist/esm/index-min.js","../../lib/constants.js","../../lib/policy.js","../../../events/dist/esm/index-min.js","../../lib/event.js","../../lib/policy/fixed-interval-policy.js","../../lib/policy/fixed-increase-policy.js","../../lib/policy/factor-increase-policy.js","../../lib/policy/shuttle-policy.js","../../lib/task.js","../../lib/alway-task.js","../../lib/policy/fixed-backoff.js","../../lib/policy/exponential-backoff.js","../../lib/policy/linear-backoff.js","../../lib/retrier.js","../../lib/retrier-factory.js","../../lib/index.js"],"sourcesContent":["var t={constructorName:function(t){return t?.constructor?.name},defaults:function(t,...e){if(null==t)throw new TypeError('\"target\" must not be null or undefined');for(const n of e)if(null!=n)for(const e in n)void 0===t[e]&&(t[e]=n[e]);return t},extend:e,extends:e,equals:function(t,e){if(t===e)return!0;if(\"function\"==typeof t?.equals)return t.equals(e);if(\"function\"==typeof e?.equals)return e.equals(t);return!1},isBrowser:n,isNode:function(){return!n()}};function e(t,...e){if(null==t)throw new TypeError('\"target\" must not be null or undefined');for(const n of e)if(null!=n)for(const e in n)t[e]=n[e];return t}function n(){return\"undefined\"!=typeof window&&\"undefined\"!=typeof document}var r={isArray:o,isBoolean:i,isBuffer:function(t){return null!=t&&Buffer.isBuffer(t)},isFunction:s,isInstance:u,isIterable:function(t){return null!=t&&\"function\"==typeof t[Symbol.iterator]},isDate:function(t){return null!=t&&t instanceof Date},isError:function(t){return null!=t&&t instanceof Error},isMap:function(t){return null!=t&&\"object\"==typeof t&&t.constructor===Map},isWeakMap:function(t){return null!=t&&\"object\"==typeof t&&t.constructor===WeakMap},isNumber:h,isPositive:l,isNegative:a,isNotNegative:c,isNil:f,isNullOrUndefined:function(t){return null==t},isNull:p,isUndefined:y,isPlainObject:w,isObject:g,isPromise:d,isRegExp:function(t){return null!=t&&\"object\"==typeof t&&t.constructor===RegExp},isSet:function(t){return null!=t&&\"object\"==typeof t&&t.constructor===Set},isWeakSet:function(t){return null!=t&&\"object\"==typeof t&&t.constructor===WeakSet},isStream:function(t){return null!=t&&\"function\"==typeof t.pipe},isString:m,isSymbol:N,isPrimitive:function(t){return null!==t&&(\"string\"==typeof t||\"number\"==typeof t||\"boolean\"==typeof t)}};function o(t){return Array.isArray(t)}function i(t){return\"boolean\"==typeof t}function s(t){return\"function\"==typeof t}function u(t){return null!=t&&\"object\"==typeof t&&!w(t)}function f(t){return null==t}function l(t){return!!h(t)&&t>0}function c(t){return!!h(t)&&t>=0}function a(t){return!!h(t)&&t<0}function p(t){return null===t}function y(t){return void 0===t}function h(t){return null!=t&&\"number\"==typeof t}function g(t){return null!=t&&\"object\"==typeof t}function w(t){return null!==t&&\"object\"==typeof t&&(t.constructor===Object||void 0===t.constructor)}function d(t){return null!=t&&\"function\"==typeof t.then}function m(t){return null!=t&&\"string\"==typeof t}function N(t){return null!=t&&\"symbol\"==typeof t}var b={assertNumber:v,assertPositive:function(t,e){if(!l(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Not Positive: ${t}`)},assertNegative:function(t,e){if(!a(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Not Negative: ${t}`)},assertNotNegative:function(t,e){if(!c(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Not \"0 or Positive\": ${t}`)},assertBoolean:function(t,e){if(!i(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Not Boolean: type=${typeof t} value=${JSON.stringify(t)}`)},assertObject:E,assertPlainObject:function(t,e){if(!w(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Not PlainObject: type=${typeof t} value=${JSON.stringify(t)}`)},assertSymbol:function(t,e){if(!N(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Not Symbol: type=${typeof t} value=${JSON.stringify(t)}`)},assertFunction:S,assertInstance:function(t,e){if(!u(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Not Class Instance: type=${typeof t} value=${JSON.stringify(t)}`)},assertPromise:P,assertNil:function(t,e){if(!f(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Neither Null nor Undefined: type=${typeof t} value=${JSON.stringify(t)}`)},assertNotNil:function(t,e){if(f(t))throw new Error((e?'\"'+e+'\" ':\" \")+\"Should Not Nil\")},assertNull:function(t,e){if(!p(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Not Null: type=${typeof t} value=${JSON.stringify(t)}`)},assertNotNull:function(t,e){if(p(t))throw new Error((e?'\"'+e+'\" ':\" \")+\"Should Not Null\")},assertUndefined:function(t,e){if(!y(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Not Undefined: type=${typeof t} value=${JSON.stringify(t)}`)},assertString:O,assertArray:$,assertStringOrSymbol:function(t,e){if(!m(t)&&!N(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Not String or Symbol: type=${typeof t} value=${JSON.stringify(t)}`)}};function $(t,e){if(!Array.isArray(t))throw new Error(`${e?e+\"\":\" \"}Not Array: type=${typeof t} value=${JSON.stringify(t)}`)}function O(t,e){if(!m(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Not String: type=${typeof t} value=${JSON.stringify(t)}`)}function v(t,e){if(!h(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Not Number: type=${typeof t} value=${JSON.stringify(t)}`)}function E(t,e){if(!g(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Not Object: type=${typeof t} value=${JSON.stringify(t)}`)}function S(t,e){if(!s(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Not Function: type=${typeof t} value=${JSON.stringify(t)}`)}function P(t,e){if(!d(t))throw new Error(`${e?'\"'+e+'\" ':\" \"}Not Promise: type=${typeof t} value=${JSON.stringify(t)}`)}var j={isEmpty:x,assertNotEmpty:k,isBlank:T,assertNotBlank:function(t){if(T(t))throw new Error(`Blank String: ${t}`)},capitalize:function(t){if(O(t),0===t.length)return t;const e=t.charAt(0),n=e.toUpperCase();return e===n?t:n+t.slice(1)},decapitalize:function(t){if(O(t),0===t.length)return t;const e=t.charAt(0),n=e.toLowerCase();return e===n?t:n+t.slice(1)},splitWithFixedLength:function(t,e,n=\" \"){if(O(t),v(e),O(n),0===t.length)return[];if(e<=0)throw new Error(\"length muse >=0\");if(t.length<e)return[t.padEnd(e,n)];const r=[];for(let o=0;o<t.length;o+=e){const i=t.substring(o,o+e);r.push(i.padEnd(e,n))}return r},split:function(t,...e){O(t);if(0===t.length)return[];const n=[...e];0===e.length&&e.push(\",\");const r=J(t,...n);if(0===r.length)return[];const o=[];let i=\"\",s=0;for(const{marker:e,index:n}of r)i=t.substring(s,n),o.push(i),s=n+e.length;return i=t.substring(s),o.push(i),o},findMarkerPositions:function(t,...e){if(O(t),0===e.length)throw new Error(\"At least one marker must be provided\");const n=[];for(const r of new Set(e)){if(x(r))continue;O(r);let e=t.indexOf(r);for(;-1!==e;)n.push({marker:r,index:e}),e=t.indexOf(r,e+r.length)}return n.sort((t,e)=>t.index-e.index),n},findMarkerPositionsRegex:J,substringBefore:function(t,e){if(O(t),O(e),0===t.length||0===e.length)return;const n=t.indexOf(e);if(-1===n)return;return t.substring(0,n)},substringBeforeLast:function(t,e){if(O(t),O(e),0===t.length||0===e.length)return;const n=t.lastIndexOf(e);if(-1===n)return;return t.substring(0,n)},substringAfter:function(t,e){if(O(t),O(e),0===t.length||0===e.length)return;const n=t.indexOf(e);if(-1===n)return;return t.substring(n+e.length)},substringAfterLast:function(t,e){if(O(t),O(e),0===t.length||0===e.length)return;const n=t.lastIndexOf(e);if(-1===n)return;return t.substring(n+e.length)},substringBetween:function(t,e,n){k(t),k(e),k(n);const r=t.indexOf(e);if(-1===r)return;const o=t.indexOf(n,r+e.length);if(-1===o)return;return t.substring(r+e.length,o)},substringBetweenGreedy:function(t,e,n){k(t),k(e),k(n);const r=t.indexOf(e);if(-1===r)return;const o=t.lastIndexOf(n);if(-1===o||o<=r)return;return t.substring(r+e.length,o)},substringsBetween:function(t,e,n){k(t),k(e),k(n);const r=[];let o=0;for(;;){const i=t.indexOf(e,o);if(-1===i)break;const s=t.indexOf(n,i+e.length);if(-1===s)break;r.push(t.substring(i+e.length,s)),o=s+n.length}return r}};function x(t){return null==t||(O(t),0===t.length)}function k(t){if(x(t))throw new Error(`Empty String: ${t}`)}function T(t){return null==t||(O(t),0===t.trim().length)}function J(t,...e){if(O(t),0===e.length)throw new Error(\"At least one marker must be provided\");const n=[...new Set(e.filter(t=>null!=t))].map(t=>(O(t),t.replace(/[.*+?^${}()|[\\]\\\\]/g,\"\\\\$&\"))),r=new RegExp(n.map(t=>`(${t})`).join(\"|\"),\"g\"),o=[];let i=null;for(;null!==(i=r.exec(t));){for(let t=1;t<i.length;t++)if(i[t]){o.push({marker:e[t-1],index:i.index});break}0===i[0].length&&r.lastIndex++}return o}var A={quiet:function(t){S(t);try{const e=t();return d(e)?e.catch(()=>{}):e}catch(t){}},quietKeepError:function(t,e){S(t),$(e);try{const n=t();return d(n)?n.catch(t=>e.push(t)):n}catch(t){e.push(t)}}},B={defer:U,delay:function(t,e){h(t)?(e=t,t=Promise.resolve()):null==t&&null==e&&(e=1,t=Promise.resolve());null!=t&&P(t),v(e=e??1e3);const n=U(),r=Date.now();return t.then((...t)=>{const o=Date.now()-r;o<e?setTimeout(()=>n.resolve(...t),e-o):n.resolve(...t)}).catch(t=>{const o=Date.now()-r;o<e?setTimeout(()=>n.reject(t),e-o):n.reject(t)}),n.promise},timeout:function(t,e,n){P(t),v(e=e??1);const r=U(e,n),o=Date.now();return t.then((...t)=>{Date.now()-o<=e?r.resolve(...t):r.reject(new Error(n??`Promise Timeout: ${e}ms`))}).catch(t=>{!r.resolved&&!r.rejected&&r.reject(t)}),r.promise},allSettled:C,returnValuePromised:I,series:async function(t){$(t);const e=[];for(const n of t)S(n),e.push(await n());return e},seriesAllSettled:async function(t){$(t);const e=[];for(const n of t){S(n);try{e.push({ok:!0,result:await n()})}catch(t){e.push({ok:!1,result:t})}}return e},parallel:async function(t,e=5){if($(t),v(e),e<=0)throw new Error(`Invalid maxParallel: ${e}, should > 0`);t.forEach(t=>S(t));const n=[];if(t.length<=e){const e=await Promise.all(t.map(t=>I(t)));return n.push(...e),n}const r=[];for(const o of t)if(S(o),r.push(o),r.length>=e){const t=await Promise.all(r.map(t=>I(t)));n.push(...t),r.length=0}if(r.length>0&&r.length<e){const t=await Promise.all(r.map(t=>I(t)));n.push(...t)}return n},parallelAllSettled:async function(t,e=5){if($(t),v(e),e<=0)throw new Error(`Invalid maxParallel: ${e}, should > 0`);t.forEach(t=>S(t));const n=[];if(t.length<=e){const e=await C(t.map(t=>I(t)));return n.push(...e),n}const r=[];for(const o of t)if(S(o),r.push(o),r.length>=e){const t=await C(r.map(t=>I(t)));n.push(...t),r.length=0}if(r.length>0&&r.length<e){const t=await C(r.map(t=>I(t)));n.push(...t)}return n}};function U(t=-1,e){v(t);const n={};let r;return t>=0&&(n.timerHandler=r=setTimeout(()=>{clearTimeout(r),n.timerCleared=!0,n.reject(new Error(e??`Promise Timeout: ${t}ms`))},t),n.timerHandler=r),n.promise=new Promise((t,e)=>{n.resolve=(...e)=>{null!=r&&(clearTimeout(r),n.timerCleared=!0),n.resolved=!0,t(...e)},n.reject=t=>{null!=r&&(clearTimeout(r),n.timerCleared=!0),n.rejected=!0,e(t)}}),n.promise.cancel=()=>{null!=r&&(clearTimeout(r),n.timerCleared=!0),n.rejected=!0,n.canceled=n.promise.canceled=!0,n.reject(new Error(\"Cancelled\"))},n}async function C(t){$(t);const e=await Promise.allSettled(t),n=[];for(const t of e)\"fulfilled\"===t.status&&n.push({ok:!0,result:t.value}),\"rejected\"===t.status&&n.push({ok:!1,result:t.reason});return n}function I(t){try{const e=t();return d(e)?e:Promise.resolve(e)}catch(t){return Promise.reject(t)}}const{isPlainObject:M}=r;var q={proxy:D,newProxyInstance:function(t,e,n,r=!0){const o=D(t,n,r);return Reflect.construct(o,e??[])}};function D(t,e,n=!0){if(\"function\"!=typeof t)throw new TypeError(`Not Class: type=${typeof t}, value=${JSON.stringify(t)}`);if(null!=e){if(!M(e))throw new TypeError(`Not PropertyHandler: type=${typeof e}, value=${JSON.stringify(e)}`);const{get:t,set:n}=e;if(null!=t&&\"function\"!=typeof t)throw new TypeError(`Not PropertyHandler.get: type=${typeof t}, value=${JSON.stringify(t)}`);if(null!=n&&\"function\"!=typeof n)throw new TypeError(`Not PropertyHandler.set: type=${typeof n}, value=${JSON.stringify(n)}`)}const r={construct(t,r,o){const i=Reflect.construct(t,r);return new Proxy(n?Object.preventExtensions(i):i,e??{})}};return new Proxy(t,r)}var L={proxy:function(t,e,n=!0){if(f(t)||!g(t)||o(t))throw new TypeError(`Not Object: type=${typeof t}, value=${JSON.stringify(t)}`);return new Proxy(n?Object.preventExtensions(t):t,e??{})}};function R(t){E(t,\"obj\");const e=new Set;let n=t;for(;n&&n!==Object.prototype;){const r=Object.getOwnPropertyNames(n);for(const n of r)\"constructor\"!==n&&\"function\"==typeof t[n]&&e.add(n);n=Object.getPrototypeOf(n)}return[...new Set(e)]}var H={getMethodsOfClass:function(t){S(t,\"cls\");const e=new Set;let n=t.prototype;for(;n&&n!==Object.prototype;){const t=Object.getOwnPropertyNames(n);for(const r of t)\"constructor\"!==r&&\"function\"==typeof n[r]&&e.add(r);n=Object.getPrototypeOf(n)}return[...new Set(e)]},getStaticMethodsOfClass:function(t){S(t,\"cls\");const e=new Set;let n=t;for(;n&&n!==Object.getPrototypeOf(Object);){const t=Object.getOwnPropertyNames(n);for(const r of t)\"function\"==typeof n[r]&&e.add(r);n=Object.getPrototypeOf(n)}return[...e]},getMethods:R,getMethodsOfObject:R},W={LangUtils:t,StringUtils:j,TypeUtils:r,TypeAssert:b,ExecUtils:A,PromiseUtils:B,Lang:t,Type:r,Exec:A,ClassProxyUtils:q,InstanceProxyUtils:L,ReflectUtils:H};export{q as ClassProxyUtils,A as Exec,A as ExecUtils,L as InstanceProxyUtils,t as Lang,t as LangUtils,B as PromiseUtils,H as ReflectUtils,j as StringUtils,r as Type,b as TypeAssert,r as TypeUtils,W as default};\n//# sourceMappingURL=index-min.js.map\n","// module vars\nexport const DefaultMinInterval = 50\nexport const DefaultMaxInterval = 30 * 1000 // 30s\nexport const DefaultMaxRetries = 3\nexport default {\n DefaultMinInterval,\n DefaultMaxInterval,\n DefaultMaxRetries\n}\n","// internal\nimport { TypeAssert, TypeUtils } from '@creejs/commons-lang'\n// owned\nimport { DefaultMaxInterval, DefaultMinInterval } from './constants.js'\n\n// module vars\nconst { assertPositive, assertNotNegative } = TypeAssert\nconst { isNumber } = TypeUtils\n\nexport default class Policy {\n /**\n * Creates a new Policy instance with specified retry bounds.\n */\n constructor () {\n this._min = DefaultMinInterval\n this._max = DefaultMaxInterval\n this._nextInterval = this._min\n this._jitter = 0\n }\n\n get jitter () {\n return this._jitter\n }\n\n set jitter (jitter) {\n assertNotNegative(jitter, 'jitter')\n this._jitter = jitter\n }\n\n /**\n * Copies settings to target policy.\n * 1. range\n * 2. nextInterval value\n * @param {Policy} targetPolicy - The policy to modify.\n */\n copyPolicySettingTo (targetPolicy) {\n targetPolicy.range(this._min, this._max)\n targetPolicy._nextInterval = this._nextInterval\n }\n\n /**\n * Sets a fixed interval retry policy.\n }\n\n /**\n * Sets the minimum and maximum intervals for retries.\n * @param {number} min - Minimum delay in milliseconds (must be positive and less than max)\n * @param {number} max - Maximum delay in milliseconds (must be positive and greater than min)\n * @returns {this} Returns the Retrier instance for chaining\n * @throws {Error} If min is not less than max or if values are not positive\n */\n range (min, max) {\n assertPositive(min, 'min')\n assertPositive(max, 'max')\n if (min >= max) {\n throw new Error('min must < max')\n }\n this._min = min\n if (this._nextInterval < this._min) {\n this._nextInterval = this._min\n }\n this._max = max\n if (this._nextInterval > this._max) {\n this._nextInterval = this._max\n }\n return this\n }\n\n /**\n * Sets the minimum retry delay in milliseconds.\n * 1. will change currentInterval to min\n * @param {number} min - The minimum delay (must be positive and less than max).\n * @returns {this} The retrier instance for chaining.\n * @throws {Error} If min is not positive or is greater than/equal to max.\n */\n min (min) {\n assertPositive(min, 'min')\n if (min >= this._max) {\n throw new Error('min must < max')\n }\n this._min = min\n this._nextInterval = this._min\n return this\n }\n\n /**\n * Sets the maximum retry retry delay in milliseconds.\n * @param {number} max - The maximum delay (must be positive and greater than min).\n * @throws {Error} If max is not greater than min.\n * @returns {this} The retrier instance for chaining.\n */\n max (max) {\n assertPositive(max, 'max')\n if (max <= this._min) {\n throw new Error('max must > min')\n }\n this._max = max\n if (this._nextInterval > this._max) {\n this._nextInterval = this._max\n }\n return this\n }\n\n reset () {\n this._nextInterval = this._min\n return this\n }\n\n /**\n * Interval ms of next execution\n * @param {number} retries current retry times\n * @returns {number}\n */\n generate (retries) {\n const rtnVal = this._nextInterval\n this._increase(retries)\n return rtnVal\n }\n\n /**\n * @param {number} retries current retry times\n * @returns {number}\n */\n _increase (retries) {\n const generated = this._next(retries)\n if (!isNumber(generated)) {\n throw new Error('Generated Next Interval Not Number')\n }\n const nextInterval = this._jitter <= 0 ? generated : generated + Math.floor(Math.random() * this._jitter)\n if (nextInterval < this._min) {\n return (this._nextInterval = this._min)\n } else if (nextInterval > this._max) {\n return (this._nextInterval = this._max)\n }\n return (this._nextInterval = nextInterval)\n }\n\n /**\n * subclass should implement this method\n * @param {number} retries current retry times\n * @returns {number} The interval in milliseconds to wait before the next retry attempt.\n * @protected\n */\n _next (retries) {\n throw new Error('Not Impled Yet')\n }\n}\nexport { Policy as PolicyType }\n","var e={isFunction:t,isNil:s};function t(e){return\"function\"==typeof e}function s(e){return null==e}function n(e){return null!=e&&\"string\"==typeof e}var r={assertNumber:function(e,t){if(!function(e){return null!=e&&\"number\"==typeof e}(e))throw new Error(`${t?'\"'+t+'\" ':\" \"}Not Number: type=${typeof e} value=${JSON.stringify(e)}`)},assertFunction:function(e,s){if(!t(e))throw new Error(`${s?'\"'+s+'\" ':\" \"}Not Function: type=${typeof e} value=${JSON.stringify(e)}`)},assertNotNil:function(e,t){if(s(e))throw new Error((t?'\"'+t+'\" ':\" \")+\"Should Not Nil\")},assertString:function(e,t){if(!n(e))throw new Error(`${t?'\"'+t+'\" ':\" \"}Not String: type=${typeof e} value=${JSON.stringify(e)}`)},assertStringOrSymbol:function(e,t){if(!n(e)&&!function(e){return null!=e&&\"symbol\"==typeof e}(e))throw new Error(`${t?'\"'+t+'\" ':\" \"}Not String or Symbol: type=${typeof e} value=${JSON.stringify(e)}`)}};const i=\"DOwner$#$\",{assertFunction:l,assertNotNil:a}=r;class o{constructor(e,t,s=!1){a(e,\"event\"),l(t,\"callback\"),this._event=e,this._callback=t,this._isOnce=!!s,this._owner=void 0}set owner(e){this._owner=e}get owner(){return this._owner===i?void 0:this._owner}get event(){return this._event}get isOnce(){return this._isOnce}isSameCallback(e){return this._callback===e}get callback(){return this._callback}invoke(...e){try{return this._callback(...e)}finally{if(this._isOnce)try{this._event._remove(this)}catch(e){console.warn(e)}}}listener(...e){return this.invoke(...e)}}const{isFunction:c,isNil:h}=e,{assertStringOrSymbol:u,assertFunction:_}=r;class f{static get DefaultOwner(){return i}constructor(e){u(e,\"eventName\"),this._name=e,this._callbacks=new Set,this._listeners=[],this._callback2Listeners=new Map,this._listener2Owner=new Map,this._owner2Listeners=new Map}get name(){return this._name}isEmpty(){return 0===this._callbacks.size}rawListeners(){return[...this._listeners]}listenerCount(e){return null==e?this._listeners.length:this._callback2Listeners.get(e)?.size??0}callbacks(){return[...this.rawListeners().map(e=>e.callback)]}emit(...e){if(0===this._listeners.length)return!1;for(const t of[...this._listeners])t.invoke(...e);return!0}hasListener(e){return!!c(e)&&this._callbacks.has(e)}hasOwner(e){return!h(e)&&this._owner2Listeners.has(e)}addListener(e,t){return this._addListener(e,t,!1,!1)}prependListener(e,t){return this._addListener(e,t,!1,!0)}addOnceListener(e,t){return this._addListener(e,t,!0,!1)}prependOnceListener(e,t){return this._addListener(e,t,!0,!0)}_addListener(e,t,s,n){if(h(e))return!1;_(e),this._callbacks.has(e)||this._callbacks.add(e),t=t??i;const r=new o(this,e,s);r.owner=t,n?this._listeners.unshift(r):this._listeners.push(r),this._listener2Owner.set(r,t);let l=this._callback2Listeners.get(e);null==l&&(l=new Set,this._callback2Listeners.set(e,l)),l.add(r);let a=this._owner2Listeners.get(t);return null==a&&(a=new Set,this._owner2Listeners.set(t,a)),a.add(r),!0}removeListener(e){if(h(e))return!1;if(!this._callbacks.has(e))return!1;this._callbacks.delete(e);const t=this._callback2Listeners.get(e);if(null==t)return!1;this._callback2Listeners.delete(e);for(const e of t){-1!==this._listeners.indexOf(e)&&this._listeners.splice(this._listeners.indexOf(e),1);const t=this._listener2Owner.get(e);if(null==t)continue;this._listener2Owner.delete(e);const s=this._owner2Listeners.get(t);null!=s&&(s.delete(e),0===s.size&&this._owner2Listeners.delete(t))}return!0}_remove(e){const t=this._listeners.indexOf(e);-1!==t&&this._listeners.splice(t,1);const{callback:s}=e,n=this._callback2Listeners.get(s);null!=n&&(n.delete(e),0===n.size&&(this._callback2Listeners.delete(s),this._callbacks.delete(s)));const r=this._listener2Owner.get(e);if(null==r)return;this._listener2Owner.delete(e);const i=this._owner2Listeners.get(r);null!=i&&(i.delete(e),0===i.size&&this._owner2Listeners.delete(r))}removeAllListeners(e){if(h(e))return this._callbacks.clear(),this._listeners.length=0,this._callback2Listeners.clear(),this._listener2Owner.clear(),this._owner2Listeners.clear(),this;const t=this._owner2Listeners.get(e);if(null==t)return this;this._owner2Listeners.delete(e);for(const e of t){-1!==this._listeners.indexOf(e)&&this._listeners.splice(this._listeners.indexOf(e),1),this._listener2Owner.delete(e);const{callback:t}=e,s=this._callback2Listeners.get(t);null!=s&&(s.delete(e),0===s.size&&(this._callback2Listeners.delete(t),this._callbacks.delete(t)))}return this}}const{isNil:m}=e,{assertString:d,assertFunction:L,assertNumber:w,assertStringOrSymbol:v,assertNotNil:g}=r,p=[\"on\",\"once\",\"addListener\",\"prependListener\",\"prependOnceListener\",\"off\",\"offAll\",\"offOwner\",\"removeAllListeners\",\"removeListener\",\"emit\",\"setMaxListeners\",\"getMaxListeners\",\"hasOwner\",\"listeners\",\"listenerCount\",\"eventNames\",\"rawListeners\"];let b=10;class O{static mixin(e){const t=new O;e.__emitter=t;for(const s of p){const n=t[s];e[s]=n.bind(t)}return e}static get defaultMaxListeners(){return b}static set defaultMaxListeners(e){w(e),b=e??10}constructor(){this._name2Event=new Map,this._maxListeners=b}addListener(e,t,s){return this.on(e,t,s)}prependListener(e,t,s){d(e),L(t),this._checkMaxListeners(e);return this._getOrCreateEvent(e).prependListener(t,s),this}prependOnceListener(e,t,s){d(e),L(t),this._checkMaxListeners(e);return this._getOrCreateEvent(e).prependOnceListener(t,s),this}emit(e,...t){const s=this._name2Event.get(e);return null!=s&&!s.isEmpty()&&(s.emit(...t),!0)}eventNames(){return[...this._name2Event.keys()]}getMaxListeners(){return this._maxListeners}listenerCount(e,t){v(e,\"eventName\");const s=this._name2Event.get(e);return null==s||s.isEmpty()?0:s.listenerCount(t)}listeners(e){v(e,\"eventName\");const t=this._name2Event.get(e);return null==t||t.isEmpty()?[]:t.callbacks()}off(e,t){const s=this._name2Event.get(e);return null==s?this:(s.removeListener(t),s.isEmpty()?(this._name2Event.delete(e),this):this)}offAll(e,t){v(e,\"eventName\");const s=this._name2Event.get(e);return null==s?this:(s.removeAllListeners(t),s.isEmpty()?(this._name2Event.delete(e),this):this)}offOwner(e){g(e,\"owner\");const t=[...this._name2Event.values()];for(const s of t)s.removeAllListeners(e),s.isEmpty()&&this._name2Event.delete(s.name);return this}on(e,t,s){d(e),L(t),this._checkMaxListeners(e);return this._getOrCreateEvent(e).addListener(t,s),this}_checkMaxListeners(e){let t=0;0!==this._maxListeners&&this._maxListeners!==1/0&&(t=this.listenerCount(e))>=this._maxListeners&&console.warn(`maxlistenersexceededwarning: Possible EventEmitter memory leak detected. ${t} ${e} listeners added to [${this}]. Use emitter.setMaxListeners() to increase limit`)}once(e,t,s){d(e),L(t);return this._getOrCreateEvent(e).addOnceListener(t,s),this}rawListeners(e){return this._name2Event.get(e)?.rawListeners()||[]}removeAllListeners(e,t){return this.offAll(e,t)}removeListener(e,t){return this.off(e,t)}setMaxListeners(e){if(w(e),e<0)throw new RangeError(\"maxListeners must >=0\");return this._maxListeners=e,this}_getOrCreateEvent(e){if(this._name2Event.has(e))return this._name2Event.get(e);const t=new f(e);return this._name2Event.set(e,t),t}hasOwner(e){if(m(e))return!1;for(const t of this._name2Event.values())if(t.hasOwner(e))return!0;return!1}}export{O as EventEmitter,O as default};\n//# sourceMappingURL=index-min.js.map\n","export const Start = 'start' // retry started\nexport const Stop = 'stop' // retry stopped\nexport const Retry = 'retry' // one retry began\nexport const Success = 'success' // one task running succeeded\nexport const Failure = 'failure' // one task ran failed\nexport const Timeout = 'timeout' // total timeout\nexport const TaskTimeout = 'task-timeout' // one task timed out\nexport const Completed = 'complete' // all retries completed\nexport const MaxRetries = 'max-retries' // Reach the max retries\n\nexport default {\n Start,\n Retry,\n Success,\n Failure,\n Timeout,\n TaskTimeout,\n Stop,\n Completed,\n MaxRetries\n}\n","// 3rd\n// internal\nimport { TypeAssert } from '@creejs/commons-lang'\n// owned\nimport Policy from '../policy.js'\n// module vars\nconst { assertPositive } = TypeAssert\nexport default class FixedIntervalPolicy extends Policy {\n /**\n * Creates a fixed interval retry policy with the specified interval.\n * @param {number} interval - The fixed interval (in milliseconds) between retry attempts.\n */\n constructor (interval) {\n super()\n assertPositive(interval, 'interval')\n this._interval = interval\n }\n\n set interval (interval) {\n assertPositive(interval, 'interval')\n this._interval = interval\n }\n\n get interval () {\n return this._interval\n }\n\n /**\n * Interval ms of next execution\n * @param {number} retries\n * @returns {number}\n * @throws {Error} Always throws \"Not Implemented Yet\" error.\n */\n _next (retries) {\n return this.interval\n }\n}\n\nexport { FixedIntervalPolicy as FixedIntervalPolicyType }\n","// 3rd\n// internal\nimport { TypeAssert } from '@creejs/commons-lang'\n// owned\nimport Policy from '../policy.js'\n// module vars\nconst { assertPositive } = TypeAssert\nexport default class FixedIncreasePolicy extends Policy {\n /**\n * each call to _next() increases the interval by \"increasement\".\n * @param {number} increasement - The fixed interval (in milliseconds) between retry attempts.\n */\n constructor (increasement) {\n super()\n assertPositive(increasement, 'increasement')\n this._increasement = increasement\n }\n\n set increasement (increasement) {\n assertPositive(increasement, 'increasement')\n this._increasement = increasement\n }\n\n get increasement () {\n return this._increasement\n }\n\n /**\n * Interval ms of next execution\n * @param {number} retries\n * @returns {number}\n */\n _next (retries) {\n if (this._nextInterval >= this._max) {\n return this._max\n }\n return this._nextInterval + this.increasement\n }\n}\nexport { FixedIncreasePolicy as FixedIncreasePolicyType }\n","// 3rd\n// internal\nimport { TypeAssert } from '@creejs/commons-lang'\n// owned\nimport Policy from '../policy.js'\n// module vars\nconst { assertPositive } = TypeAssert\n\nexport default class FactoreIncreasePolicy extends Policy {\n /**\n * each call to _next() increases the interval by lastInterval * factor\n * @param {number} factor - the increasement factor, >= 1\n */\n constructor (factor) {\n super()\n assertPositive(factor, 'factor')\n if (factor < 1) {\n throw new Error('factor must be >= 1')\n }\n this._factor = factor\n }\n\n set factor (factor) {\n assertPositive(factor, 'factor')\n if (factor < 1) {\n throw new Error('factor must be >= 1')\n }\n this._factor = factor\n }\n\n get factor () {\n return this._factor\n }\n\n /**\n * Interval ms of next execution\n * @param {number} retries\n * @returns {number}\n */\n _next (retries) {\n if (this._nextInterval >= this._max) {\n return this._max\n }\n return this._nextInterval * this.factor\n }\n}\nexport { FactoreIncreasePolicy as FactoreIncreasePolicyType }\n","// 3rd\n// internal\nimport { TypeAssert } from '@creejs/commons-lang'\n\n// owned\nimport Policy from '../policy.js'\n// module vars\nconst { assertPositive } = TypeAssert\n\nexport default class ShuttlePolicy extends Policy {\n /**\n * the inteval value shuttles between min and max\n * @param {number} stepLength - the step length to change\n */\n constructor (stepLength) {\n super()\n assertPositive(stepLength, 'stepLength')\n this._stepLength = stepLength\n this.increasement = stepLength\n }\n\n set stepLength (stepLength) {\n assertPositive(stepLength, 'stepLength')\n this._stepLength = stepLength\n this.increasement = stepLength\n }\n\n get stepLength () {\n return this._stepLength\n }\n\n /**\n * Interval ms of next execution\n * @param {number} retries\n * @returns {number}\n * @throws {Error} Always throws \"Not Implemented Yet\" error.\n */\n _next (retries) {\n const nextInterval = this._nextInterval + this.increasement\n if (nextInterval >= this._max) {\n this.increasement = -this.stepLength\n return this._max\n } else if (nextInterval <= this._min) {\n this.increasement = this.stepLength\n return this._min\n }\n return nextInterval\n }\n}\n\nexport { ShuttlePolicy as ShuttlePolicyType }\n","import { TypeAssert } from '@creejs/commons-lang'\n// owned\n\n/**\n * @typedef {import('./retrier.js').default} Retrier\n */\n\n// module vars\nconst { assertNotNil, assertFunction } = TypeAssert\nexport default class Task {\n /**\n * Creates a new Task instance.\n * @param {Retrier} retrier - The retrier instance.\n * @param {Function} task - The function to be executed as the task.\n */\n constructor (retrier, task) {\n assertNotNil(retrier, 'retrier')\n assertFunction(task, 'task')\n this.retrier = retrier\n this.task = task\n this.result = undefined\n this.error = undefined\n }\n\n get failed () {\n return this.error != null\n }\n\n get succeeded () {\n return this.error == null\n }\n\n /**\n * Executes the task with the given retry parameters.\n * 1. if execution throw error, keep error in this.error\n * 2. if execution return value, keep it in this.result\n * 3. always return Promise<void>\n * @param {number} retries - The number of retries attempted so far.\n * @param {number} latence - The current latency ms.\n * @param {number} nextInterval - The next interval ms.\n * @returns {Promise<void>} The result of the task execution.\n */\n async execute (retries, latence, nextInterval) {\n try {\n this.result = await this.task(retries, latence, nextInterval)\n this.error = undefined\n } catch (e) {\n this.error = e\n }\n }\n\n dispose () {\n // @ts-ignore\n this.retrier = undefined\n }\n}\n\nexport { Task as TaskType }\n","// owned\nimport Task from './task.js'\n\n/**\n * @typedef {import('./retrier.js').default} Retrier\n */\n\nexport default class AlwaysTask extends Task {\n /**\n * Checks if the given task is an instance of AlwaysTask.\n * @param {*} task - The task to check.\n * @returns {boolean} True if the task is an instance of AlwaysTask, false otherwise.\n */\n static isAlwaysTask (task) {\n return task instanceof AlwaysTask\n }\n\n /**\n * Creates an AlwaysTask instance.\n * @param {Retrier} retrier - The retrier instance to use for retry logic\n * @param {Function} task - The task function to execute\n * @param {boolean} resetRetryPolicyAfterSuccess - Whether to reset retry policy after successful execution\n */\n constructor (retrier, task, resetRetryPolicyAfterSuccess) {\n super(retrier, task)\n this.resetPolicy = resetRetryPolicyAfterSuccess\n }\n\n /**\n * Executes the task with the given retry parameters.\n * @param {number} retries - The number of retries attempted so far.\n * @param {number} latence - The current latency ms.\n * @param {number} nextInterval - The next interval ms.\n * @returns {Promise<*>} The result of the task execution.\n */\n async execute (retries, latence, nextInterval) {\n await super.execute(retries, latence, nextInterval)\n if (this.succeeded && this.resetPolicy) {\n this.retrier.resetRetryPolicy()\n }\n }\n}\n\nexport { AlwaysTask as AlwaysTaskType }\n","// internal\nimport { TypeAssert } from '@creejs/commons-lang'\n// owned\nimport FixedInterval from './fixed-interval-policy.js'\n// module vars\nconst { assertNotNegative } = TypeAssert\n/**\n * @class FixedBackoff\n */\nexport default class FixedBackoff extends FixedInterval {\n /**\n * Creates a fixed backoff policy with optional jitter.\n * @param {number} fixedInterval - The fixed interval between retries in milliseconds.\n * @param {number} [jitter=500] - The maximum random jitter to add to the interval in milliseconds.\n */\n constructor (fixedInterval, jitter = 500) {\n super(fixedInterval)\n assertNotNegative(jitter, 'jitter')\n this._jitter = jitter ?? 500\n }\n}\n\nexport { FixedBackoff as FixedBackoffType }\n","// internal\nimport { TypeAssert } from '@creejs/commons-lang'\n// owned\nimport FactoreIncreasePolicy from './factor-increase-policy.js'\n\n// module vars\nconst { assertNotNegative } = TypeAssert\n/**\n * @class ExponentialBackoffPolicy\n */\nexport default class ExponentialBackoffPolicy extends FactoreIncreasePolicy {\n /**\n * Creates an exponential backoff policy with optional jitter.\n * @param {number} [jitter=500] - Maximum jitter in milliseconds to add to backoff intervals.\n */\n constructor (jitter = 500) {\n super(2)\n assertNotNegative(jitter, 'jitter')\n this._jitter = jitter ?? 500\n }\n}\n\nexport { ExponentialBackoffPolicy as ExponentialBackoffPolicyType }\n","// internal\nimport { TypeAssert } from '@creejs/commons-lang'\n// owned\nimport FixedIncreasePolicy from './fixed-increase-policy.js'\n// module vars\nconst { assertNotNegative } = TypeAssert\n/**\n * @class LinearBackoff\n */\nexport default class LinearBackoff extends FixedIncreasePolicy {\n /**\n * Creates a linear backoff policy with optional jitter.\n * @param {number} increasement - The base increasement value for backoff.\n * @param {number} [jitter=500] - The maximum jitter value to add to backoff (default: 500).\n */\n constructor (increasement, jitter = 500) {\n super(increasement)\n assertNotNegative(jitter, 'jitter')\n this._jitter = jitter ?? 500\n }\n}\n\nexport { LinearBackoff as LinearBackoffType }\n","// internal\nimport { TypeAssert, TypeUtils, PromiseUtils } from '@creejs/commons-lang'\nimport { EventEmitter } from '@creejs/commons-events'\n\n// owned\n// eslint-disable-next-line no-unused-vars\nimport Policy from './policy.js'\nimport Event from './event.js'\nimport FixedIntervalPolicy from './policy/fixed-interval-policy.js'\nimport FixedIncreasePolicy from './policy/fixed-increase-policy.js'\nimport FactoreIncreasePolicy from './policy/factor-increase-policy.js'\nimport ShuttlePolicy from './policy/shuttle-policy.js'\nimport Task from './task.js'\nimport AlwaysTask from './alway-task.js'\nimport { DefaultMaxRetries } from './constants.js'\nimport FixedBackoff from './policy/fixed-backoff.js'\nimport ExponentialBackoffPolicy from './policy/exponential-backoff.js'\nimport LinearBackoff from './policy/linear-backoff.js'\n\n// module vars\nconst { assertPositive, assertString, assertFunction, assertNumber } = TypeAssert\nconst { isNil } = TypeUtils\nconst TaskTimoutFlag = '!#@%$&^*'\n\n/**\n * @extends EventEmitter\n */\nexport default class Retrier {\n /**\n * Creates a new Retrier instance with a fixed interval policy.\n * @param {number} [fixedInterval=1000] - The fixed interval in milliseconds between retry attempts. Defaults to 1000ms if not provided.\n */\n constructor (fixedInterval) {\n EventEmitter.mixin(this)\n /**\n * @type {Policy}\n */\n this._policy = new FixedIntervalPolicy(fixedInterval ?? 1000)\n this._maxRetries = DefaultMaxRetries\n this._currentRetries = 1\n /**\n * Timetou for total operation\n * @type {number}\n */\n this._timeout = 120000 // 120s\n /**\n * Timetou for single task\n */\n this._taskTimeout = 2000 // 20s\n this._name = 'unamed' // Retrier name\n\n /**\n * A Deferred Object as Singal to prevent Task concurrent start\n * @type {{resolve:Function, reject:Function, promise: Promise<*>}|undefined}\n */\n this._taskingFlag = undefined\n\n /**\n * A Deferred Object as Singal to prevent Task concurrent stop\n * @type {{resolve:Function, reject:Function, promise: Promise<*>}|undefined}\n */\n this._breakFlag = undefined\n /**\n * Reason for break\n * @type {Error|undefined}\n */\n this._breakReason = undefined\n }\n\n get running () {\n return !isNil(this._taskingFlag)\n }\n\n /**\n * Sets the name of the retrier.\n * @param {string} retrierName - The name to assign to the retrier.\n * @returns {this} The retrier instance for chaining.\n */\n name (retrierName) {\n assertString(retrierName, 'retrierName')\n this._name = retrierName\n return this\n }\n\n /**\n * Sets the retry attempts to be infinite by setting max retries to maximum safe integer.\n * @returns {Object} The retrier instance for chaining.\n */\n infinite () {\n this._maxRetries = Infinity\n return this\n }\n\n /**\n * Sets the maximum number of retry attempts.\n * @param {number} times - The maximum number of retries.\n * @returns {this} The Retrier instance for chaining.\n */\n times (times) {\n return this.maxRetries(times)\n }\n\n /**\n * Sets the maximum number of retry attempts.\n * @param {number} maxRetries - The maximum number of retries (must be positive).\n * @returns {this} The retrier instance for chaining.\n */\n maxRetries (maxRetries) {\n assertPositive(maxRetries, 'maxRetries')\n this._maxRetries = maxRetries\n return this\n }\n\n /**\n * Sets the minimum retry delay in milliseconds.\n * @param {number} min - The minimum delay (must be positive and less than max).\n * @returns {this} The retrier instance for chaining.\n * @throws {Error} If min is not positive or is greater than/equal to max.\n */\n min (min) {\n this._policy.min(min)\n return this\n }\n\n /**\n * Sets the maximum retry retry delay in milliseconds.\n * @param {number} max - The maximum delay (must be positive and greater than min).\n * @throws {Error} If max is not greater than min.\n * @returns {this} The retrier instance for chaining.\n */\n max (max) {\n this._policy.max(max)\n return this\n }\n\n /**\n * Sets the minimum and maximum intervals for retries.\n * @param {number} min - Minimum delay in milliseconds (must be positive and less than max)\n * @param {number} max - Maximum delay in milliseconds (must be positive and greater than min)\n * @returns {Retrier} Returns the Retrier instance for chaining\n * @throws {Error} If min is not less than max or if values are not positive\n */\n range (min, max) {\n this._policy.range(min, max)\n return this\n }\n\n /**\n * Sets a fixed interval retry policy.\n * @param {number} fixedInterval - The fixed interval in milliseconds between retries.\n * @returns {Retrier} The Retrier instance for chaining.\n */\n fixedInterval (fixedInterval) {\n const oldPolicy = this._policy\n if (oldPolicy instanceof FixedIntervalPolicy) {\n oldPolicy.interval = fixedInterval\n return this\n }\n const newPolicy = new FixedIntervalPolicy(fixedInterval)\n oldPolicy?.copyPolicySettingTo(newPolicy)\n newPolicy.reset()\n this._policy = newPolicy\n return this\n }\n\n /**\n * sets a fixed backoff strategy.\n * @param {number} fixedInterval - The fixed interval between retries in milliseconds.\n * @param {number} [jitter=500] - The maximum jitter to add to the interval in milliseconds.\n * @returns {Retrier} A retrier instance configured with fixed backoff.\n */\n fixedBackoff (fixedInterval, jitter = 500) {\n const oldPolicy = this._policy\n if (oldPolicy instanceof FixedIntervalPolicy) {\n oldPolicy.interval = fixedInterval\n oldPolicy.jitter = jitter\n return this\n }\n const newPolicy = new FixedBackoff(fixedInterval, jitter)\n oldPolicy?.copyPolicySettingTo(newPolicy)\n newPolicy.reset()\n this._policy = newPolicy\n return this\n }\n\n /**\n * Sets a fixed increase policy for retry intervals.\n * @param {number} increasement - The fixed amount to increase the interval by on each retry.\n * @returns {this} The retrier instance for chaining.\n */\n fixedIncrease (increasement) {\n const oldPolicy = this._policy\n if (oldPolicy instanceof FixedIncreasePolicy) {\n oldPolicy.increasement = increasement\n return this\n }\n const newPolicy = new FixedIncreasePolicy(increasement)\n oldPolicy?.copyPolicySettingTo(newPolicy)\n newPolicy.reset()\n this._policy = newPolicy\n return this\n }\n\n /**\n * Sets a fixed increase policy for retry intervals.\n * @param {number} increasement - The fixed amount to increase the interval by on each retry.\n * @param {number} [jitter=500] - The maximum jitter to add to the interval in milliseconds.\n * @returns {this} The retrier instance for chaining.\n */\n linearBackoff (increasement, jitter = 500) {\n const oldPolicy = this._policy\n if (oldPolicy instanceof LinearBackoff) {\n oldPolicy.increasement = increasement\n oldPolicy.jitter = jitter\n return this\n }\n const newPolicy = new LinearBackoff(increasement, jitter)\n oldPolicy?.copyPolicySettingTo(newPolicy)\n newPolicy.reset()\n this._policy = newPolicy\n return this\n }\n\n /**\n * Sets a fixed increase factor for retry delays.\n * @param {number} factor - The multiplier for delay increase between retries.\n * @returns {this} The retrier instance for method chaining.\n */\n factorIncrease (factor) {\n const oldPolicy = this._policy\n if (oldPolicy instanceof FactoreIncreasePolicy) {\n oldPolicy.factor = factor\n return this\n }\n const newPolicy = new FactoreIncreasePolicy(factor)\n oldPolicy?.copyPolicySettingTo(newPolicy)\n newPolicy.reset()\n this._policy = newPolicy\n return this\n }\n\n /**\n * Creates a new Retrier instance with exponential-backoff strategy.\n * @param {number} [jitter]\n * @returns {Retrier} A new Retrier instance\n */\n exponentialBackoff (jitter = 500) {\n const oldPolicy = this._policy\n if (oldPolicy instanceof ExponentialBackoffPolicy) {\n oldPolicy.jitter = jitter\n return this\n }\n const newPolicy = new ExponentialBackoffPolicy(jitter)\n oldPolicy?.copyPolicySettingTo(newPolicy)\n newPolicy.reset()\n this._policy = newPolicy\n return this\n }\n\n /**\n * Sets a shuttle retry policy with the given step length.\n * @param {number} stepLength - The interval between retry attempts.\n * @returns {this} The Retrier instance for chaining.\n */\n shuttleInterval (stepLength) {\n const oldPolicy = this._policy\n if (oldPolicy instanceof ShuttlePolicy) {\n oldPolicy.stepLength = stepLength\n return this\n }\n const newPolicy = new ShuttlePolicy(stepLength)\n oldPolicy?.copyPolicySettingTo(newPolicy)\n newPolicy.reset()\n this._policy = newPolicy\n return this\n }\n\n /**\n * Sets the timeout duration for each Task execution.\n * 1. must > 0\n * @param {number} timeout - The timeout duration in milliseconds.\n * @returns {Object} The retrier instance for chaining.\n */\n taskTimeout (timeout) {\n assertPositive(timeout, 'timeout')\n this._taskTimeout = timeout\n return this\n }\n\n /**\n * Sets the timeout duration for all retries.\n * 1. <= 0 - no timeout\n * 2. \\> 0 - timeout duration in milliseconds\n * @param {number} timeout - The timeout duration in milliseconds.\n * @returns {Object} The retrier instance for chaining.\n */\n timeout (timeout) {\n assertNumber(timeout, 'timeout')\n this._timeout = timeout\n return this\n }\n\n /**\n * Sets the task function to be retried.\n * @param {Function} task - The function to be executed and retried on failure.\n * @returns {this} Returns the retrier instance for chaining.\n */\n task (task) {\n assertFunction(task, 'task')\n this._task = new Task(this, task)\n return this\n }\n\n /**\n * alias of {@linkcode Retrier.task()}\n * @param {Function} task - The function to be executed and retried\n * @return {this}\n */\n retry (task) {\n this.task(task)\n return this\n }\n\n /**\n * Executes the given task, and never stop\n * 1. if the task fails, will retry it after the interval generated by RetryPolicy\n * 2. if the task succeeds, reset RetryPolicy to Minimum Interval and continue to run the task\n * @param {Function} task - The async function to execute and retry.\n * @param {boolean} [resetAfterSuccess=false] - Whether to reset retry counters after success.\n * @returns {this} The Retrier instance for chaining.\n */\n always (task, resetAfterSuccess = false) {\n this._task = new AlwaysTask(this, task, resetAfterSuccess)\n return this\n }\n\n /**\n * Starts the retry process.\n * @returns {Promise<*>}\n */\n async start () {\n if (this._task == null) {\n throw new Error('No Task to Retry')\n }\n if (this._taskingFlag != null) {\n return this._taskingFlag.promise\n }\n const startAt = Date.now()\n let lastError = null\n // @ts-ignore\n this.emit(Event.Start, startAt)\n this._taskingFlag = PromiseUtils.defer()\n let latency = null\n while (true) {\n // need to stop?\n if (this._breakFlag != null) {\n this._taskingFlag.reject(this._breakReason)\n break\n }\n\n latency = Date.now() - startAt\n\n // total timeout?\n if (!isInfinite(this._timeout) && latency >= this._timeout) { // total timeout\n // @ts-ignore\n this.emit(Event.Timeout, this._currentRetries, latency, this._timeout)\n // always task, treat as success, resolve the whole promise with <void>\n if (AlwaysTask.isAlwaysTask(this._task)) {\n this._taskingFlag.resolve()\n break\n }\n this._taskingFlag.reject(lastError ?? new Error(`Timeout \"${this._timeout}\" Exceeded`))\n break\n }\n\n // @ts-ignore\n this.emit(Event.Retry, this._currentRetries, latency)\n const task = this._task // take task, it may be changed in events' callback functions\n const nextDelay = this._policy.generate(this._currentRetries)\n try {\n try {\n await PromiseUtils.timeout(task.execute(this._currentRetries, latency, nextDelay), this._taskTimeout, TaskTimoutFlag)\n } catch (err) {\n // @ts-ignore\n if (err.message === TaskTimoutFlag) {\n // @ts-ignore\n this.emit(Event.TaskTimeout, this._currentRetries, latency, this._taskTimeout)\n }\n throw err\n }\n // @ts-ignore\n if (task.failed) {\n lastError = task.error\n throw task.error\n }\n const rtnVal = task.result\n // @ts-ignore\n this.emit(Event.Success, rtnVal, this._currentRetries, latency)\n\n // Not AwaysTask, we can finish all the retries with success\n if (!AlwaysTask.isAlwaysTask(task)) {\n this._taskingFlag.resolve(rtnVal)\n break\n }\n // AwaysTask, continue to run the task\n } catch (e) {\n // @ts-ignore\n this.emit(Event.Failure, e, this._currentRetries, latency)\n }\n const nextRetries = ++this._currentRetries\n // next retry, max retries reached?\n if (this._currentRetries > this._maxRetries) {\n // @ts-ignore\n this.emit(Event.MaxRetries, nextRetries, this._maxRetries)\n // always task, treat as success, resolve the whole promise with <void>\n if (AlwaysTask.isAlwaysTask(task)) {\n this._taskingFlag.resolve()\n break\n }\n this._taskingFlag.reject(lastError ?? new Error(`Max Retries Exceeded, Retring ${this._currentRetries} times > max ${this._maxRetries}`))\n break\n }\n await PromiseUtils.delay(nextDelay)\n }\n this._taskingFlag.promise.finally(() => {\n this.resetRetryPolicy()\n this._taskingFlag = undefined\n const spent = Date.now() - startAt\n // @ts-ignore\n this.emit(Event.Completed, this._currentRetries, spent)\n })\n return this._taskingFlag.promise\n }\n\n /**\n * Stops the retrier with an optional reason. If already stopping, returns the existing break promise.\n * @param {Er