UNPKG

@hisorange/resistor

Version:

Versatily resource load throttler with extensible strategies, configuration and virtual thread management.

101 lines (100 loc) 3.97 kB
/// <reference types="node" /> import EventEmitter from 'events'; import { EVENTS } from './events'; import { IAnalytics } from './interfaces/analytics.interface'; import { IResistorConfig } from './interfaces/config.interface'; import { DeepPartial } from './interfaces/deep-partial.type'; import { EventListener } from './interfaces/event-listener.type'; import { IFlushConfig } from './interfaces/flush-config.interface'; import { WaitPass } from './interfaces/wait-pass.interface'; import { IWorker } from './interfaces/worker.interface'; export declare class Resistor<I> implements Pick<EventEmitter, 'on' | 'once' | 'off'> { /** * Temporary buffer to store the records until the worker flushes them. */ protected buffer: I[]; /** * Continouosly delayed timer to ensure the flush is called reguraly even if * the buffer would not reach it's maximum size. */ protected flushTimer: NodeJS.Timer | undefined; /** * Stores the active flush workers, this is how the script tracks the active "threads". */ protected vThreads: Promise<void>[]; /** * When the maximum thread reached, the script will enqueue the flush workers in a FIFO logic, * after a thread finished, it will shift the first waiting execution and allows its execution. */ protected waitQueue: WaitPass[]; /** * Stores the manageging configurations. */ protected config: IResistorConfig; /** * Usage analytics, designed to be used with healthchecks. */ protected _analytics: IAnalytics; /** * NodeJS event emitter. */ protected emitter: EventEmitter; /** * Store the reference to the worker function. */ protected worker: IWorker<I>; /** * Initialize a configured resistor. */ constructor(worker: IWorker<I>, config?: DeepPartial<IResistorConfig>); /** * Register an event listener for every occasion when the event emitted. */ on(event: EVENTS, listener: EventListener): EventEmitter; /** * Register an event listener for one event emitting. */ once(event: EVENTS, listener: EventListener): EventEmitter; /** * Deregister the given event listener. */ off(event: EVENTS, listener: EventListener): EventEmitter; /** * Register an auto flush timeout in case the buffer is not loaded to the full * and we need to trigger an flush by timer. * * This is always being pushed out when the buffer reaches the maximum size. */ protected register(): void; /** * Call this before shutdown to empty the last buffer and remove the timer. * Also useful to await this because only resolves when the buffer, queue, and threads are empty. * * @example process.on('SIGTERM', resistor.deregister.bind(resistor)); * @example process.on('SIGKILL', resistor.deregister.bind(resistor)); */ deregister(): Promise<void>; /** * Initiate a flush, this will schedule the current buffer to a virtual thread. * * Important! By default the flush will not wait for the worker to execute so the caller * can push the records until the active threads are populated without waiting. * * But when the deregister called the script will wait for the last flush to be handled. */ flush(config?: IFlushConfig): Promise<void>; /** * Handles the actual thread scheduling, the flush simply just packages an execution * and the scheduler is responsible to manage the queue and the threads. */ protected schedule(job: (threadId: number) => Promise<void>, waitForWorker: boolean): Promise<void>; /** * Push a record to the buffer, returns a promise which should be awaited so * the caller can be slowed down when the threads are overloaded. */ push(record: I): Promise<void>; /** * Reads the current analytics. */ get analytics(): IAnalytics; }