durabull
Version:
A durable workflow engine built on top of BullMQ and Redis
90 lines (89 loc) • 3.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Workflow = void 0;
const logger_1 = require("./runtime/logger");
const isAsyncGenerator = (value) => {
if (typeof value !== 'object' || value === null) {
return false;
}
const candidate = value;
return typeof candidate.next === 'function' && typeof candidate[Symbol.asyncIterator] === 'function';
};
const isPromiseLike = (value) => {
return typeof value === 'object' && value !== null && 'then' in value &&
typeof value.then === 'function';
};
class Workflow {
constructor() {
this.compensations = [];
this.parallelCompensation = false;
this.continueWithError = false;
}
addCompensation(fn) {
this.compensations.push(fn);
}
async *compensate() {
const toRun = [...this.compensations].reverse();
if (this.parallelCompensation) {
const promises = toRun.map(async (fn) => {
try {
const result = fn();
if (isAsyncGenerator(result)) {
for await (const _ of result) {
// consume generator stream to allow side effects
}
return;
}
if (isPromiseLike(result)) {
await result;
return;
}
else {
void result;
}
}
catch (error) {
if (!this.continueWithError) {
throw error;
}
const logger = (0, logger_1.getLogger)();
logger.error('Compensation error (ignored)', error);
}
});
await Promise.all(promises);
yield;
}
else {
for (const fn of toRun) {
try {
const result = fn();
if (isAsyncGenerator(result)) {
for await (const value of result) {
yield value;
}
continue;
}
if (isPromiseLike(result)) {
yield await result;
continue;
}
yield result;
}
catch (error) {
if (!this.continueWithError) {
throw error;
}
const logger = (0, logger_1.getLogger)();
logger.error('Compensation error (ignored)', error);
}
}
}
}
setParallelCompensation(parallel) {
this.parallelCompensation = parallel;
}
setContinueWithError(continueOnError) {
this.continueWithError = continueOnError;
}
}
exports.Workflow = Workflow;