UNPKG

@emigrate/cli

Version:

Emigrate is a tool for managing database migrations. It is designed to be simple yet support advanced setups, modular and extensible.

59 lines 2.23 kB
import { setTimeout } from 'node:timers'; import prettyMs from 'pretty-ms'; import { ExecutionDesertedError, toError } from './errors.js'; import { DEFAULT_RESPITE_SECONDS } from './defaults.js'; /** * Execute a function and return a result tuple * * This is a helper function to make it easier to handle errors without the extra nesting of try/catch * If an abort signal is provided the function will reject with an ExecutionDesertedError if the signal is aborted * and the given function has not yet resolved within the given respite time (or a default of 30 seconds) * * @param fn The function to execute * @param options Options for the execution */ export const exec = async (fn, options = {}) => { try { const aborter = options.abortSignal ? getAborter(options.abortSignal, options.abortRespite) : undefined; const result = await Promise.race(aborter ? [aborter, fn()] : [fn()]); aborter?.cancel(); return [result, undefined]; } catch (error) { return [undefined, toError(error)]; } }; /** * Returns a promise that rejects after a given time after the given signal is aborted * * @param signal The abort signal to listen to * @param respite The time in milliseconds to wait before rejecting */ const getAborter = (signal, respite = DEFAULT_RESPITE_SECONDS * 1000) => { const cleanups = []; const aborter = new Promise((_, reject) => { const abortListener = () => { const timer = setTimeout(reject, respite, ExecutionDesertedError.fromReason(`Deserted after ${prettyMs(respite)}`, toError(signal.reason))); timer.unref(); cleanups.push(() => { clearTimeout(timer); }); }; if (signal.aborted) { abortListener(); return; } signal.addEventListener('abort', abortListener, { once: true }); cleanups.push(() => { signal.removeEventListener('abort', abortListener); }); }); const cancel = () => { for (const cleanup of cleanups) { cleanup(); } cleanups.length = 0; }; return Object.assign(aborter, { cancel }); }; //# sourceMappingURL=exec.js.map