uncancellable<T> method
Runs action with the cancellation held back, and waits for it.
For a step that cannot be taken back: a payment on its way to the server,
a write already on the wire. While action runs the job accepts no
cancellation it may refuse, so neither an onCancel callback nor a child
hears one, and the core waits for the body. Throws Cancelled up front
if the job is already cancelled. Held, not refused: the job accepts
the cancellation as the section closes and still ends cancelled, so what
has to happen after the step anyway belongs inside the section.
final receipt = await ctx.uncancellable(() => api.pay(order));
Sections nest, and only the outermost lets a held cancellation through,
even if action throws. A cancellation the job cannot refuse, such as a
rule an engine adds, is not held: the job ends with its reason, and the
held one never lands. Always await this call: the section belongs to the
job, not to the future.
See Holding the cancellation back on the cancellation page, and Unregistering inside the action on the cleanup rules page for a hand-over and its disown in one section.
Implementation
@override
Future<T> uncancellable<T>(FutureOr<T> Function() action) async {
// Before `throwIfFinished`: for work that outlived its job both
// complaints are true, but the call from the fork is the one to fix.
throwIfUnattended('run an uncancellable action');
throwIfFinished('run an uncancellable action');
check();
enterUncancellable();
try {
return await action();
} finally {
leaveUncancellable();
}
}