Programming & Compilers
Structured concurrency: owned tasks and completion
Structured concurrency ties child task lifetime to a scope. Trace failure policies, task scope completion, cleanup and accepted ownership transfers.

A parent operation can finish its own instructions while children it started still run, fail, or use resources the parent plans to release. Returning after a spawn therefore needs a different completion meaning from returning after the owned work has settled.
structured concurrency makes a task scope the ownership boundary for that work. Its completion contract accounts for its children and their outcomes. A cancellation request changes what those children have been asked to do; it does not establish that their execution has ended.
The examples use a hypothetical task tree with explicit failure policies. They describe lifecycle obligations without prescribing a scheduler, a coroutine implementation or interruption rules inside a state transition.
Attach child task lifetime to a resource-owning scope
Let parent P own resource R and start children A and B. A reads through R, while B produces a result that P will report. Both are owned by P's task scope in this model.
Draw the task tree P above A and B, and record which child may use R. Ownership of a task and permission to use a resource are related but distinct entries. A child can be running even after its last use of R, or can still need R after its first result becomes available.
For the scope's stated contract, P must not release R while an owned child is still permitted to use it. The required lifetime follows the actual use relationship, rather than simply whether P has reached the end of its main function.
The pipeline-backpressure guide follows payload ownership through queues, workers and output buffers, showing that removing an item from a queue does not release its backing object. That is useful context for child task lifetime: the parent needs to know which child still holds permission to use a resource. The related memory account limits retained bytes; the scope contract here additionally requires observed child outcomes and valid cleanup timing.
If A starts its own child A1, A's scope needs to account for that descendant before reporting its own settlement under the model. P can then account for A through that nested contract. An unobserved descendant would break the ownership chain.
The tree supplies obligations beyond naming the spawned children. The scope needs a mechanism and evidence for observing the terminal outcomes of the work it owns.
Contrast return after spawn with return after settlement
In an unaccounted execution, P opens R at time zero, starts A and B at one, and returns at two. Its cleanup releases R while A is still running. A's later use of R no longer fits the intended resource lifetime.
B might also fail after P has returned. If no owner observes that failure, P's earlier success report does not describe the result of the child work it initiated. The application has lost an outcome as well as a lifecycle boundary.
In the structured model, P reaches the end of its main work but remains within the scope's completion obligation. It observes the owned children settling, performs the permitted cleanup, and reports the outcome required by its contract.
Settlement does not mean every child succeeded. A child can return a value, fail, or reach a terminal cancellation outcome. What matters is that the owner records the relevant result and no longer treats still-running owned work as completed.
The parent can complete with an error after accounting for its children. Lifecycle completion and application success are separate statements.
How task scope completion follows the sibling-failure policy
Use a first policy in which failure of one child triggers cancellation requests to the remaining siblings. Suppose A fails at time three while B is still running.
P observes A's failure and requests B's cancellation at three. B does not settle until five. P must continue accounting for B between those events rather than report the entire scope complete at the request time.
After B's terminal outcome is observed, the scope can perform its required cleanup and report the failure outcome defined by this policy. The report should retain A's actual failure and B's actual termination result.
Use another policy that waits for all children without requesting sibling cancellation when one fails. A still fails at three, but B continues and returns its result at eight. P reports according to the policy after both outcomes are settled.
These policies make different choices about sibling work. Neither can be inferred from the word structured alone. The implementation and caller contract must identify which failures are propagated and which outcomes are retained.
Python's asyncio TaskGroup provides a documented policy example. Its context manager waits for all group tasks on exit. An ordinary child failure other than CancelledError requests cancellation of remaining group tasks, and their completion is awaited before grouped failures are reported. The documentation also names special handling for KeyboardInterrupt and SystemExit. Those are properties of that API, not a universal policy or a general mechanism for moving a running child between owners.
A scope can also define how several child failures are reported. Ignoring a later failure because an earlier one already exists is a reporting choice that needs a specification; it is not evidence that the later child succeeded.
Cancellation request, termination, and observation are separate events
A cancellation request can become visible to B while B is still performing permitted work or cleanup. Request delivery is therefore not a terminal child result.
B's termination is another event. P then needs to observe and account for it under the scope's completion contract. A log saying cancellation sent does not supply that observation.
The runtime-code-replacement guide traces old active frames and retained callbacks after a public entry selects new code. That surviving-reference graph helps separate task scope completion from old-code retirement. Joining the children owned by one scope does not prove that an outside callback can no longer invoke an old function. The related guide concerns version and state compatibility; this model must first identify exactly which work its parent owns.
If B does not terminate promptly under the permitted execution model, the scope remains responsible for its outstanding work. A timeout can mark the result unresolved or invoke another defined ownership action, but it cannot manufacture a terminal outcome.
The application should state what unresolved completion means to the caller. A distinct unresolved caller status can leave continued ownership under another defined request contract. It is not a completed task scope while its owned children remain unsettled.
The stopping mechanism depends on the task contract. Completion evidence must remain truthful when requested cancellation and actual termination differ.
Cleanup has its own completion conditions
After child settlement, P may still have resource cleanup to perform. If that cleanup is part of the promised operation, the scope's report needs to account for its actual result as well.
Suppose B finishes at five, but releasing R fails under the model's resource contract. Reporting every obligation fulfilled at five would omit the cleanup result. The child tree may be settled while the resource obligation remains unresolved.
Conversely, successfully releasing one resource does not establish that every child terminated. Resource cleanup and task settlement need their own records, joined by the permission conditions that make cleanup safe.
A failure path should therefore preserve which children settled, which outcomes were observed, and which resource obligations remain. One generic done flag loses the distinctions the scope was meant to enforce.
Long-lived work needs a deliberate new owner
Some work is intended to outlive P. Let service child C continue as a long-lived operation rather than one of P's finite request tasks. Its lifetime requires another explicit owner Q under this model.
A deliberate transfer identifies Q, establishes that Q accepted responsibility, and gives C resource access that remains valid under Q's lifetime. Removing C from P's local list without establishing those conditions is accidental detachment.
If C still borrows R from P, changing its task-owner label does not extend R's actual lifetime. The transfer must either establish valid longer-lived resource ownership or stop that dependency before P releases R.
For example, Q can own a distinct resource RQ and establish that C now uses it under the service contract. The transition needs an observed acceptance and resource-use relationship, not just a plan that Q will handle it later.
Q must also observe C's failures and eventual termination according to the service's contract. The service owner retains observation duties for the long-lived work, including its outstanding outcome.
Once the defined transfer is complete, P's completion can exclude C under that stated ownership rule. The evidence should name the accepting owner and transferred obligations so the exclusion is reviewable.
Use the tree to locate unobserved work
Consider A starting A1 and reporting success before A1 settles. If P treats A's success as proof of the whole descendant branch, A1's remaining work becomes invisible at the parent boundary.
The nested scope contract prevents that shortcut by making A's settlement account for its owned descendants. If A1 is intentionally transferred elsewhere, that transfer needs the same explicit ownership evidence as C's service case.
This is a local ownership argument, not a distributed termination detector. The model knows which tasks each scope owns and which outcomes it has observed. It does not infer global system quiescence from an empty queue or absence of messages.
The distinction keeps scope completion tied to defined obligations. A separate background service can remain active after P completes when another owner genuinely holds it; an unnoticed descendant cannot be excluded by that reasoning.
Verify the promised completion boundary
Preserve the parent-child tree, resource permissions and failure policy. For each owned child, record whether it was spawned, asked to cancel, terminated, observed, or deliberately transferred under the contract.
For the sibling-cancellation history, the check must reject a whole-scope completion claim at time three while B remains running until five. For the wait-all history, it must retain B's later result without erasing A's earlier failure.
Inspect resource release against the last permitted child use and report any required cleanup result separately. For long-lived work, verify the new owner's acceptance instead of treating detachment as settlement.
The Lenovo IdeaPad 15.6-inch FHD touch laptop is listed with a Core i5-1334U processor, 16GB DDR4 memory and 512GB SSD. It provides a computing-workspace example for recording parent and child events. A record prepared there still needs the actual ownership tree and completion policy; the hardware specifications cannot identify those application relationships.
The ASUS Vivobook 14 FHD laptop is described with an Intel Core 5 120U processor and 16GB DDR4. A child-settlement table can be inspected in that computing context, but the table must name termination, observation and cleanup as separate events. The device description supplies no task-group result or guarantee about resource release.
For the sibling-cancellation history, keep A's failure at three, the request sent to B at three and B's terminal result at five as separate events. Record the parent's observation and resource settlement before reporting the scope outcome. For the wait-all history, preserve B's result at eight alongside A's failure. These records make the selected structured concurrency contract assessable at the point where the caller receives its result.