symfonic.capabilities.delegation.lifecycle¶
lifecycle ¶
Releasing the children the parent built — and only those.
The ownership rule is the whole design. A child the parent compiled from a spec holds resources the parent caused to exist (a checkpointer pool, background consolidation work) and nobody else will ever release them. A child the caller handed over belongs to the caller, who may well be using it elsewhere; closing it on the parent's shutdown would break a perfectly healthy agent.
Two verbs, in one order, for one reason. flush waits for fire-and-forget
background work; aclose releases resources. Flushing after closing would
wait for work whose backing store had already gone away, which is why the order
is fixed here rather than left to each caller — and why a flush that fails
still reaches the close, from an inner finally. A child closed with its
consolidation unflushed loses memory the adopter believes was written; a child
left open because its flush raised leaks a pool forever. The second is worse.
ChildLifecycle ¶
Owns the teardown of the children a compilation constructed.
Source code in src/symfonic/capabilities/delegation/lifecycle.py
owned
property
¶
The children this lifecycle will release.
Still readable after teardown. Idempotency is a flag, not an emptied list, because "what did this parent own?" is a question asked during an investigation of a shutdown that went wrong.
aclose
async
¶
Release each owned child's resources. Idempotent.
flush
async
¶
Await each child's pending background work.
Never raises for a child's sake. One child whose consolidation is
wedged must not strand the others' — including their aclose, which
runs after this.
Source code in src/symfonic/capabilities/delegation/lifecycle.py
shutdown
async
¶
Flush, then close, whatever the flush did.
The inner finally is the contract: a raising flush cannot skip the
close. Both phases report into one record so a caller sees everything
that went wrong, not only whatever failed last.