durable-execution
Version:
A durable task engine for running tasks durably and resiliently
124 lines (121 loc) • 3.15 kB
JavaScript
// src/cancel.ts
import { getErrorMessage } from "@gpahal/std/errors";
// src/errors.ts
import { CustomError } from "ts-custom-error";
var DurableExecutionError = class extends CustomError {
/**
* Whether the error is retryable.
*/
isRetryable;
/**
* @param message - The error message.
* @param isRetryable - Whether the error is retryable.
*/
constructor(message, isRetryable = true) {
super(message);
this.isRetryable = isRetryable;
}
getErrorType() {
return "generic";
}
};
var DurableExecutionCancelledError = class extends DurableExecutionError {
/**
* @param message - The error message.
*/
constructor(message) {
super(message ?? "Task cancelled", false);
}
getErrorType() {
return "cancelled";
}
};
// src/logger.ts
function createConsoleLogger(name) {
return {
debug: (message) => console.debug(`DEBUG [${name}] ${message}`),
info: (message) => console.info(`INFO [${name}] ${message}`),
error: (message, error) => console.error(`ERROR [${name}] ${message}`, error)
};
}
// src/cancel.ts
function createCancelSignal({
abortSignal,
logger
} = {}) {
logger = logger ?? createConsoleLogger("CancelSignal");
let isCancelled = abortSignal?.aborted ?? false;
const subscribers = /* @__PURE__ */ new Set();
const cancel = () => {
if (abortSignal) {
abortSignal.removeEventListener("abort", cancel);
}
if (isCancelled) {
return;
}
isCancelled = true;
for (const fn of subscribers) {
try {
fn();
} catch (error) {
logger.error(`Error in cancel signal subscriber: ${getErrorMessage(error)}`);
}
}
subscribers.clear();
};
if (abortSignal) {
abortSignal.addEventListener("abort", cancel);
}
const cancelSignal = {
onCancelled: (fn) => {
if (isCancelled) {
fn();
} else {
subscribers.add(fn);
}
},
clearOnCancelled: (fn) => {
subscribers.delete(fn);
},
isCancelled: () => isCancelled
};
return [cancelSignal, cancel];
}
function createTimeoutCancelSignal(timeoutMs, { logger } = {}) {
const [cancelSignal, cancel] = createCancelSignal({ logger });
setTimeout(() => cancel(), timeoutMs);
return cancelSignal;
}
function createCancellablePromise(promise, signal, cancelledError) {
if (!signal) {
return promise;
}
const getCancelledError = () => {
if (!cancelledError) {
return new DurableExecutionCancelledError();
}
if (cancelledError instanceof DurableExecutionError) {
return cancelledError;
}
return new DurableExecutionCancelledError(getErrorMessage(cancelledError));
};
return new Promise((resolve, reject) => {
if (signal.isCancelled()) {
reject(getCancelledError());
return;
}
const onCancelled = () => {
reject(getCancelledError());
};
signal.onCancelled(onCancelled);
promise.then(resolve, reject).finally(() => {
signal.clearOnCancelled(onCancelled);
});
});
}
export {
createCancelSignal,
createCancellablePromise,
createTimeoutCancelSignal
};
//# sourceMappingURL=cancel.js.map