API reference › @evolu/common › Task › unabortableMask
function unabortableMask<T, E, D>(
fn: (
restore: <T2, E2, D2>(task: Task<T2, E2, D2>) => Task<T2, E2, D2>,
) => Task<T, E, D>,
): Task<T, E, D>;
Defined in: packages/common/src/Task.ts:5184
Like unabortable, but provides restore for child Tasks that
should run with the previous abort mask.
Use this for acquire/use/release flows where acquire and release must finish
once started, while use should remain abortable. Child Tasks inherit the mask
unless they are wrapped with restore() before scheduling.
An abort request before the mask Task starts prevents entering the mask. Once
the body starts, plain child Tasks inherit the mask, so acquire and release
can run after abort. Start release Tasks directly in the original mask's
finally; do not wrap release in a nested unabortableMask, which is a new
critical-section entry and may not start after abort.
AsyncDisposableStack is often enough for ordinary acquire/release. Use
it inside unabortableMask when masked acquire/release spans multiple or
conditional resources.
Example
import {
assertEqual,
assertFalse,
assertTrue,
AbortError,
createRun,
ok,
unabortableMask,
waitForAbort,
type Task,
} from "@evolu/common";
interface Resource {
readonly id: string;
}
const acquire: Task<Resource> = () => ok({ id: "resource-1" });
const operationStarted = Promise.withResolvers<void>();
const operate =
(resource: Resource): Task<never> =>
(run) => {
assertEqual(resource.id, "resource-1");
operationStarted.resolve();
return run(waitForAbort);
};
let released = false;
const release =
(_resource: Resource): Task<void> =>
(run) => {
// Release inherits the mask even after abort was requested.
assertFalse(run.signal.aborted);
released = true;
return ok();
};
await using run = createRun();
const fiber = run.abortable(
unabortableMask((restore) => async (run) => {
// Acquire with abort masked.
const resource = await run.ok(acquire);
try {
// Use with the previous abort mask restored.
return await run(restore(operate(resource)));
} finally {
// Release with abort masked.
await run.ok(release(resource));
}
}),
);
await operationStarted.promise;
fiber.abort();
const result = await fiber;
assertFalse(result.ok);
assertTrue(AbortError.is(result.error));
assertTrue(released);