@waku/sdk
Version:
A unified SDK for easy creation and management of js-waku nodes.
113 lines • 3.6 kB
JavaScript
import { Protocols } from "@waku/interfaces";
import { Logger } from "@waku/utils";
import { shouldPeerBeChanged, timeout } from "./utils.js";
const MAX_CONCURRENT_TASKS = 5;
const TASK_TIMEOUT_MS = 10_000;
const log = new Logger("sdk:retry-manager");
export class RetryManager {
intervalID = null;
retryIntervalMs;
inProgress = 0;
queue = [];
peerManager;
constructor(config) {
this.peerManager = config.peerManager;
this.retryIntervalMs = config.retryIntervalMs || 1000;
}
start() {
this.intervalID = setInterval(() => {
this.processQueue();
}, this.retryIntervalMs);
}
stop() {
if (this.intervalID) {
clearInterval(this.intervalID);
this.intervalID = null;
}
}
push(callback, maxAttempts, routingInfo) {
this.queue.push({
maxAttempts,
callback,
routingInfo
});
}
processQueue() {
if (this.queue.length === 0) {
return;
}
while (this.queue.length && this.inProgress < MAX_CONCURRENT_TASKS) {
const task = this.queue.shift();
if (task) {
this.scheduleTask(task);
}
}
}
scheduleTask(task) {
const delayedTask = async () => {
return this.taskExecutor(task);
};
// schedule execution ASAP
// need to use setTimeout to avoid blocking main execution
setTimeout(delayedTask, 100);
}
async taskExecutor(task) {
if (task.maxAttempts <= 0) {
log.warn("scheduleTask: max attempts has reached, removing from queue");
return;
}
const peerId = (await this.peerManager.getPeers({
protocol: Protocols.LightPush,
pubsubTopic: task.routingInfo.pubsubTopic
}))[0];
if (!peerId) {
log.warn("scheduleTask: no peers, putting back to queue");
this.queue.push({
...task,
maxAttempts: task.maxAttempts - 1
});
return;
}
try {
this.inProgress += 1;
const response = await Promise.race([
timeout(TASK_TIMEOUT_MS),
task.callback(peerId)
]);
if (response?.failure) {
throw Error(response.failure.error);
}
log.info("scheduleTask: executed successfully");
if (task.maxAttempts === 0) {
log.warn("scheduleTask: discarded a task due to limit of max attempts");
return;
}
this.queue.push({
...task,
maxAttempts: task.maxAttempts - 1
});
}
catch (_err) {
const error = _err;
log.error("scheduleTask: task execution failed with error:", error);
if (shouldPeerBeChanged(error.message)) {
await this.peerManager.renewPeer(peerId, {
protocol: Protocols.LightPush,
pubsubTopic: task.routingInfo.pubsubTopic
});
}
if (task.maxAttempts === 0) {
log.warn("scheduleTask: discarded a task due to limit of max attempts");
return;
}
this.queue.push({
...task,
maxAttempts: task.maxAttempts - 1
});
}
finally {
this.inProgress -= 1;
}
}
}
//# sourceMappingURL=retry_manager.js.map