redis-smq-common
Version:
Provides essential components and utilities shared across RedisSMQ packages.
88 lines • 3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Backoff = void 0;
const index_js_1 = require("../runnable/index.js");
const index_js_2 = require("../errors/index.js");
const index_js_3 = require("../timer/index.js");
const backoff_config_js_1 = require("./backoff-config.js");
class Backoff extends index_js_1.Runnable {
constructor(logger, config = {}) {
super();
this.attempts = 0;
this.logger = logger.createLogger(this.constructor.name);
this.config = backoff_config_js_1.BackoffConfig.parseConfig(config);
this.timer = new index_js_3.Timer(this.logger);
this.logger.debug(`Backoff initialized: baseDelay=${this.config.baseDelay}ms, maxDelay=${this.config.maxDelay}ms`);
}
runTask(task, callback) {
if (!this.isOperational()) {
return callback(new Error('Backoff is not operational'));
}
this.attempts++;
task((err, result) => {
if (err) {
if (err instanceof index_js_2.AbortError) {
return callback(err);
}
this.logger.debug(`Operation failed:`, err.message);
if (this.config.maxAttempts &&
this.attempts >= this.config.maxAttempts) {
return callback(err);
}
this.scheduleRetry(task, callback);
return;
}
this.reset();
callback(null, result);
});
}
scheduleRetry(task, callback) {
if (!this.isOperational()) {
return callback(new Error('Backoff is not operational'));
}
const delay = this.calculateNextDelay();
this.timer.schedule(() => {
this.runTask(task, callback);
}, delay);
}
calculateNextDelay() {
const { baseDelay, maxDelay, jitter } = this.config;
let delay = this.getNextDelay(baseDelay, this.attempts);
delay = Math.max(delay, baseDelay);
if (jitter) {
const range = delay * 0.2;
delay = delay + (Math.random() * range * 2 - range);
}
delay = Math.min(delay, maxDelay);
return Math.max(1, Math.floor(delay));
}
goingUp() {
return super.goingUp().concat([(cb) => this.timer.run(cb)]);
}
goingDown() {
return [
(cb) => {
this.reset();
this.timer.shutdown(cb);
},
].concat(super.goingDown());
}
getConfig() {
return Object.assign({}, this.config);
}
execute(task, callback) {
if (!this.isOperational()) {
return callback(new Error('Backoff instance is not operational'));
}
this.runTask(task, callback);
}
getAttempts() {
return this.attempts;
}
reset() {
this.timer.reset();
this.attempts = 0;
}
}
exports.Backoff = Backoff;
//# sourceMappingURL=backoff.js.map