pollsky
Version:
Chained Polling Library for Node.js: Friendly API with no external dependencies.
177 lines • 6.14 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const errors_1 = require("./errors");
const utils_1 = require("./utils");
const debug_1 = require("./debug");
/**
* ⛓ Chained Polling Library for Node.js
* @public
*/
class Pollsky {
constructor(asyncFn) {
/**
* The number of times the `asyncFn()` has invoked before `conditionFn()`
* returns true.
*/
this.retries = 0;
/**
*
*/
this.failures = [];
/**
* Time between the end of last retry and the next one.
* @default { value: 1000, unit: 'milliseconds' }
*/
this.pollingInterval = new utils_1.Time({
interval: 1000,
unit: 'milliseconds'
});
/**
* Instructs Pollsky to ignore errors thrown by `asyncFn`.
*/
this.isIgnoreErrors = false;
/**
* Instructs Pollsky to return a value even if master timeout is called.
*/
this.isDontThrowError = false;
this.asyncFn = asyncFn;
}
/**
* Static method created only to be exported, and thus achieve "cleaner" API.
*/
static wait(asyncFn) {
return new Pollsky(asyncFn);
}
/**
* Starts polling.
*/
async until(conditionFn) {
(0, debug_1.debug)(`Polling started. Parameters:`, {
isIgnoreErrors: this.isIgnoreErrors,
interval: this.pollingInterval,
atLeastCondition: this.atLeastDuration,
atMostDuration: this.atMostDuration
});
const result = await this.poll(this.asyncFn, conditionFn, this.retries);
if (this.atMostTimeout) {
clearTimeout(this.atMostTimeout);
}
return result;
}
/**
* Stops polling with failure when timeout is called.
*/
atMost(interval, unit) {
this.atMostDuration = new utils_1.Time({ interval, unit });
this.atMostTimeout = setTimeout(() => {
this.atMostTimeoutToBeCalled = true;
}, this.atMostDuration.toMilliseconds());
return this;
}
/**
* Makes polling wait at least a certain amount of time until the result is returned.
*/
atLeast(interval, unit) {
this.atMostDuration = new utils_1.Time({ interval, unit });
this.atLeastTimeout = setTimeout(() => {
this.atLeastTimeout = undefined;
}, this.atMostDuration.toMilliseconds());
return this;
}
/**
* Changes the default interval duration.
*/
withInterval(interval, unit) {
this.pollingInterval = new utils_1.Time({ interval, unit });
return this;
}
/**
* Causes errors thrown by `asyncFn` being ignored.
*/
dontThrowError() {
this.isDontThrowError = true;
return this;
}
/**
* Causes errors thrown by `asyncFn` being ignored.
*/
ignoreErrors() {
this.isIgnoreErrors = true;
return this;
}
/**
* The core method in this project, it basically contains the entire logic
* required for polling. Execute the given `asyncFn` function, checks if
* all of the conditions are met and handles the errors if needed be.
*/
async poll(asyncFn, conditionFn, retries) {
try {
return this.checkConditions(await this.executeAsyncFn(this.asyncFn), conditionFn);
}
catch (error) {
if (error instanceof errors_1.PollskyError) {
this.failures.push({
error: error.name,
errorMsg: error.message,
result: error.result,
timestamp: new Date().toISOString()
});
if (error instanceof errors_1.AtMostConditionError) {
throw new errors_1.PollingFailedError(this.failures);
}
if (error instanceof errors_1.ExceptionOccurredError) {
if (!this.isIgnoreErrors) {
throw new errors_1.PollingFailedError(this.failures);
}
}
await this.wait(this.pollingInterval.toMilliseconds());
return this.poll(asyncFn, conditionFn, retries + 1);
}
throw error;
}
}
/**
* Performs a single execution of `asyncFn` and wraps it with `try catch`
* in order to throw custom error and handle it properly.
*/
async executeAsyncFn(asyncFn) {
this.retries++;
try {
(0, debug_1.debug)(`Executing asyncFn()... Retry: ${this.retries}`);
return await asyncFn();
}
catch (error) {
throw new errors_1.ExceptionOccurredError(error.message, { timestamp: (0, utils_1.getTimestamp)() });
}
}
/**
* Checks if all conditions are met and if not, throws a custom error.
*/
checkConditions(result, conditionFn) {
if (this.atMostTimeoutToBeCalled) {
if (this.isDontThrowError) {
(0, debug_1.debug)('Master timeout called but the flag returnValueIfFailed is set');
(0, debug_1.debug)('Returning the last result.');
return result;
}
throw new errors_1.AtMostConditionError({ timestamp: (0, utils_1.getTimestamp)(), result: result });
}
if (conditionFn(result) === false) {
throw new errors_1.ConditionFunctionError({ timestamp: (0, utils_1.getTimestamp)(), result: result });
}
if (this.atLeastTimeout) {
throw new errors_1.AtLeastConditionError({ timestamp: (0, utils_1.getTimestamp)(), result: result });
}
(0, debug_1.debug)('Polling finished with success - conditionFn() returned `true`.');
(0, debug_1.debug)('Returning the last result.');
return result;
}
/**
* Waits certain amout of time.
*/
wait(duration) {
return new Promise(resolve => setTimeout(resolve, duration));
}
}
exports.default = Pollsky;
//# sourceMappingURL=pollsky.js.map