@nerjs/batchloader
Version:
`BatchLoader` is a tool for batching data requests with support for deduplication, caching, and parallel task management. It is designed to enhance flexibility and performance in scenarios requiring asynchronous data processing. This module was inspired b
92 lines • 3.16 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Deduplicator = void 0;
const defer_1 = require("../utils/defer");
const debug_1 = require("debug");
const errors_1 = require("../utils/errors");
const debug = (0, debug_1.default)('batchloader:deduplicator');
class Deduplicator {
constructor(runnerFn, options) {
this.runnerFn = runnerFn;
this.options = options;
this.runners = new Map();
}
async run(query, signal) {
try {
debug('run next runner');
return await this.runnerFn(query, signal);
}
catch (error) {
debug(`Aborted runner terminated with an error`);
throw error;
}
}
callError(key, error) {
const runner = this.runners.get(key);
if (runner) {
runner.defer.reject(error);
runner.controller.abort(error);
this.clearRunner(key);
}
}
clearRunner(key) {
const runner = this.runners.get(key);
if (runner) {
clearTimeout(runner.tid);
this.runners.delete(key);
}
}
createTimeout(key) {
return setTimeout(() => this.callError(key, new errors_1.TimeoutError(this.options.timeoutMs)), this.options.timeoutMs);
}
createRunner(key, query) {
const defer = new defer_1.Defer();
const controller = new AbortController();
const tid = this.createTimeout(key);
if (this.options.unrefTimeouts)
tid?.unref?.();
this.run(query, controller.signal)
.then(result => defer.resolve(result))
.catch(error => defer.reject(error));
defer.promise
.catch(() => {
if (!controller.signal.aborted)
controller.abort(new errors_1.RejectedAbortError('deduplicate'));
})
.finally(() => this.clearRunner(key));
this.runners.set(key, { defer, controller, tid });
return defer;
}
getOrCreateRunner(query) {
const key = this.options.getKey(query);
const current = this.runners.get(key);
if (current)
return current.defer;
return this.createRunner(key, query);
}
/**
* @description Adds a query to the execution queue or joins an already running request with the same key. Returns a promise with the result of the task execution.
*/
async call(query) {
debug('Call next runner');
const current = this.getOrCreateRunner(query);
return await current.promise;
}
restartTimeout(query) {
const key = this.options.getKey(query);
const runned = this.runners.get(key);
if (runned) {
clearTimeout(runned.tid);
runned.tid = this.createTimeout(key);
}
}
/**
* @description Cancels all active tasks and clears their state.
*/
clear() {
this.runners.forEach((_, key) => this.callError(key, new errors_1.SilentAbortError('deduplicate')));
this.runners.clear();
}
}
exports.Deduplicator = Deduplicator;
//# sourceMappingURL=deduplicator.js.map