run<T> method
Starts child right now, as a child of this job, ahead of whatever an
engine would have put it through.
Starts synchronously, then returns a future with the child's value after
the child, its children and its cleanup finish; a child's error or
cancellation reaches the future with its original stack trace. When the
child succeeds while the parent's body is still active, the future checks
the parent, for a cancellation and for the rules of its domain, and a
check that throws takes the value with it. So a value the child hands
over is registered on the call, with dispose or discard, and not on
the line after it: that line is never reached.
final db = await ctx.run(connect, discard: (db) => db.close());
dispose and discard work as in abandonable, and passing both is an
ArgumentError thrown before the child starts. Admission errors are
synchronous: an ArgumentError for a handle that is not a job of this
core or one an engine does not own; a StateError for a job already
started or finished, and for a call made after this job's body has ended
or from unattended work; and the parent's own Cancelled if the parent
is already cancelled. An ArgumentError or a StateError leaves child
with the code that made it: a job of Job.deferred stays unstarted.
See Running a child
and When ctx.run refuses a child
on the children page, and
Registering on arrival
on the cleanup rules page.
Implementation
@override
Future<T> run<T>(
ChildJob<T> child, {
FutureOr<void> Function(T value)? dispose,
FutureOr<void> Function(T value)? discard,
}) {
// Before the child starts: an admission error must leave nothing
// running behind it.
_oneCleanupOnly(dispose, discard);
startChild(child);
return _awaitChild(child, dispose: dispose, discard: discard);
}