UNPKG

dash-core

Version:

A foundational toolkit of types, collections, services, and architectural patterns designed to accelerate application development.

106 lines (105 loc) 4.45 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AdaptivePoller = void 0; const dash_core_1 = require("dash-core"); /** * Handles polling with adaptive intervals, adjusting delays based on success or failure. */ class AdaptivePoller { currentTimeout; currentDelay; lastErrorTime; polling = false; operation; onError; onFail; options; defaultOptions = { initialDelay: dash_core_1.TimeSpan.fromSeconds(1), maxDelay: dash_core_1.TimeSpan.fromMinutes(1), factor: 1.5, resetPeriod: dash_core_1.TimeSpan.fromMinutes(5), linearStep: dash_core_1.TimeSpan.fromSeconds(1) }; /** * Returns whether the polling operation is currently active. * @returns {boolean} True if polling is ongoing, false otherwise. */ get isPolling() { return this.polling; } /** * Creates an instance of the AdaptivePoller class. * @param {pollerOptions} options - Configuration options for the polling mechanism. * @param {TimeSpan} options.initialDelay - The initial delay before the first polling attempt. * @param {TimeSpan} options.maxDelay - The maximum delay between polling attempts. * @param {number} options.factor - The factor by which the delay will be multiplied after each failure. * @param {TimeSpan} options.resetPeriod - The period after which the delay will reset to the initial value if no errors occur. * @param {TimeSpan} options.linearStep - The step used to decrease the delay linearly on success. * @param {ServiceLogger} [options.logger] - Optional logger to log events during polling. */ constructor(options) { this.options = { ...this.defaultOptions, ...options }; this.currentDelay = this.options.initialDelay.totalMilliseconds; } /** * Starts the polling process, which continues until explicitly stopped. * @param {() => Promise<void>} operation - The operation to perform during each poll cycle. * @param {(error: Error) => void} onError - Optional callback to handle errors during polling. * @param {(error: Error) => void} onFail - Optional callback to handle failure events (when the interval exceeds maxDelay). */ start(operation, onError, onFail) { if (this.polling) return; this.polling = true; this.operation = operation; this.onError = onError; this.onFail = onFail; this.currentDelay = this.options.initialDelay.totalMilliseconds; this.runPoll(); this.options.logger?.info('AdaptivePolling started'); } /** * Stops the polling process. */ stop() { this.polling = false; clearTimeout(this.currentTimeout); this.options.logger?.info('AdaptivePolling stopped'); } async runPoll() { if (!this.polling || !this.operation) return; try { await this.operation(); const now = Date.now(); // Reset the delay if no error occurred within the reset period if (!this.lastErrorTime || (now - this.lastErrorTime) >= this.options.resetPeriod.totalMilliseconds) { const initialDelay = this.options.initialDelay.totalMilliseconds; const linearDifference = this.currentDelay - this.options.linearStep.totalMilliseconds; this.currentDelay = Math.max(initialDelay, linearDifference); } } catch (error) { this.lastErrorTime = Date.now(); this.currentDelay = this.currentDelay * this.options.factor; const resultError = error instanceof Error ? error : new Error(JSON.stringify(error)); if (this.currentDelay >= this.options.maxDelay.totalMilliseconds) { // If delay exceeds maxDelay, trigger the onFail callback this.currentDelay = this.options.maxDelay.totalMilliseconds; this.onFail?.(resultError); } else { // If an error occurred but delay is still within max, trigger the onError callback this.onError?.(resultError); } } finally { this.scheduleNextPoll(); } } scheduleNextPoll() { this.currentTimeout = setTimeout(() => this.runPoll(), this.currentDelay); } } exports.AdaptivePoller = AdaptivePoller;