axios-retryer
Version:
TypeScript-first Axios retry library with concurrency limits, request priority, token refresh, response caching, and circuit breaker plugins.
2 lines (1 loc) • 6.6 kB
JavaScript
function e(e){if(e)return e.__axiosRetryer}const t={activeTimers:0,activeRetryTimers:0},i={total:0,successes:0,failures:0};class r{constructor(e){this.getMetricsState=e,this.queueWaitHistory=[],this.retryDelayHistory=[]}recordRequestStart(e){var t;const i=this.getMetricsState();i.totalRequests++,i.requestCountsByPriority[e]=(null!==(t=i.requestCountsByPriority[e])&&void 0!==t?t:0)+1}recordQueueWait(e){this.getMetricsState().queueWaitDuration+=e,this.recordDuration(this.queueWaitHistory,e)}recordRetrySuccess(e){this.getMetricsState().successfulRetries++,this.getPriorityMetrics(e).successes++}recordRetryFailure(e,t){const i=this.getMetricsState();i.failedRetries++,t.response?t.response.status>=500?i.errorTypes.server5xx++:t.response.status>=400&&i.errorTypes.client4xx++:i.errorTypes.network++,this.getPriorityMetrics(e).failures++}recordRetryAttempt(e,t){var i;const r=this.getMetricsState();r.retryAttemptsDistribution[e]=(null!==(i=r.retryAttemptsDistribution[e])&&void 0!==i?i:0)+1,this.getPriorityMetrics(t).total++}recordRetryDelay(e){this.getMetricsState().retryDelayDuration+=e,this.recordDuration(this.retryDelayHistory,e)}reset(){const e=this.getMetricsState();e.totalRequests=0,e.successfulRetries=0,e.failedRetries=0,e.completelyFailedRequests=0,e.canceledRequests=0,e.completelyFailedCriticalRequests=0,e.errorTypes={network:0,server5xx:0,client4xx:0,cancelled:0},e.retryAttemptsDistribution={},e.requestCountsByPriority={},e.retryPrioritiesDistribution={},e.queueWaitDuration=0,e.retryDelayDuration=0,this.queueWaitHistory=[],this.retryDelayHistory=[]}recordCancellation(e=!1){const t=this.getMetricsState();t.canceledRequests++,e&&t.errorTypes.cancelled++}recordTerminalFailure(e){const t=this.getMetricsState();t.completelyFailedRequests++,e&&t.completelyFailedCriticalRequests++}buildDetailedMetrics(e){const t=this.getMetricsState(),i=t.failedRetries+t.successfulRetries;return this.pruneDurationHistory(this.queueWaitHistory),this.pruneDurationHistory(this.retryDelayHistory),{totalRequests:t.totalRequests,successfulRetries:t.successfulRetries,failedRetries:t.failedRetries,completelyFailedRequests:t.completelyFailedRequests,canceledRequests:t.canceledRequests,completelyFailedCriticalRequests:t.completelyFailedCriticalRequests,errorTypesDistribution:t.errorTypes,retryAttemptsDistribution:t.retryAttemptsDistribution,requestCountsByPriority:t.requestCountsByPriority,avgQueueWait:this.getWindowAverage(this.queueWaitHistory),avgRetryDelay:i>0?this.getWindowAverage(this.retryDelayHistory):0,priorityMetrics:Object.entries(t.retryPrioritiesDistribution).map(([e,t])=>({priority:Number(e),...t,successRate:t.total>0?t.successes/t.total*100:0,failureRate:t.total>0?t.failures/t.total*100:0})),timerHealth:{activeTimers:e.activeTimers,activeRetryTimers:e.activeRetryTimers,healthScore:e.activeTimers+2*e.activeRetryTimers}}}getPriorityMetrics(e){const t=this.getMetricsState();return t.retryPrioritiesDistribution[e]||(t.retryPrioritiesDistribution[e]={...i}),t.retryPrioritiesDistribution[e]}recordDuration(e,t){e.push({timestamp:Date.now(),durationMs:t}),this.pruneDurationHistory(e)}pruneDurationHistory(e){const t=Date.now()-3e5;for(;e.length>0&&e[0].timestamp<t;)e.shift()}getWindowAverage(e){return 0===e.length?0:e.reduce((e,t)=>e+t.durationMs,0)/e.length*.001}}class s{constructor(){this.name="MetricsPlugin",this.version="1.0.0",this.context=null,this.metrics={totalRequests:0,successfulRetries:0,failedRetries:0,completelyFailedRequests:0,canceledRequests:0,completelyFailedCriticalRequests:0,errorTypes:{network:0,server5xx:0,client4xx:0,cancelled:0},retryAttemptsDistribution:{},retryPrioritiesDistribution:{},requestCountsByPriority:{},queueWaitDuration:0,retryDelayDuration:0},this.collector=new r(()=>this.metrics),this.recorder={reset:()=>this.collector.reset(),buildDetailedMetrics:e=>this.collector.buildDetailedMetrics(e),emitMetricsUpdated:()=>this.emitMetricsUpdated()},this.onRequestQueuedListener=e=>{this.collector.recordRequestStart(e.priority),this.emitMetricsUpdated()},this.onRequestDispatchedListener=e=>{this.collector.recordQueueWait(e.queuedForMs),this.emitMetricsUpdated()},this.onRequestCancelledListener=e=>{this.collector.recordCancellation(!0),this.emitMetricsUpdated()},this.beforeRetryListener=t=>{var i,r;const s=e(t),o=null!==(i=null==s?void 0:s.priority)&&void 0!==i?i:1,c=null!==(r=null==s?void 0:s.retryAttempt)&&void 0!==r?r:1;this.collector.recordRetryAttempt(c,o),this.emitMetricsUpdated()},this.afterRetryListener=(t,i,r)=>{var s,o;const c=null!==(o=null===(s=e(t))||void 0===s?void 0:s.priority)&&void 0!==o?o:1;i?this.collector.recordRetrySuccess(c):r&&this.collector.recordRetryFailure(c,r),this.emitMetricsUpdated()},this.onRetryScheduledListener=e=>{this.collector.recordRetryDelay(e),this.emitMetricsUpdated()},this.onFailureListener=e=>{this.collector.recordTerminalFailure(!1),this.emitMetricsUpdated()},this.onBlockingRequestFailedListener=e=>{this.collector.recordTerminalFailure(!0),this.emitMetricsUpdated()},this.onRequestSucceededListener=()=>{this.emitMetricsUpdated()}}initialize(e){this.context=e,e.registerMetricsRecorder(this.recorder),e.on("onRequestQueued",this.onRequestQueuedListener),e.on("onRequestDispatched",this.onRequestDispatchedListener),e.on("onRequestCancelled",this.onRequestCancelledListener),e.on("beforeRetry",this.beforeRetryListener),e.on("afterRetry",this.afterRetryListener),e.on("onRetryScheduled",this.onRetryScheduledListener),e.on("onFailure",this.onFailureListener),e.on("onBlockingRequestFailed",this.onBlockingRequestFailedListener),e.on("onRequestSucceeded",this.onRequestSucceededListener)}onBeforeDestroyed(e){e.off("onRequestQueued",this.onRequestQueuedListener),e.off("onRequestDispatched",this.onRequestDispatchedListener),e.off("onRequestCancelled",this.onRequestCancelledListener),e.off("beforeRetry",this.beforeRetryListener),e.off("afterRetry",this.afterRetryListener),e.off("onRetryScheduled",this.onRetryScheduledListener),e.off("onFailure",this.onFailureListener),e.off("onBlockingRequestFailed",this.onBlockingRequestFailedListener),e.off("onRequestSucceeded",this.onRequestSucceededListener),e.registerMetricsRecorder(null),this.context=null}getMetrics(){var e,i;return this.collector.buildDetailedMetrics(null!==(i=null===(e=this.context)||void 0===e?void 0:e.getTimerStats())&&void 0!==i?i:t)}resetMetrics(){this.collector.reset(),this.emitMetricsUpdated()}emitMetricsUpdated(){this.context&&this.context.triggerAndEmit("onMetricsUpdated",this.getMetrics())}}function o(){return new s}export{r as MetricsCollector,s as MetricsPlugin,o as createMetricsPlugin};