Skip to content

Close path: resolve during finalization, failed finalizers, cancelled close #567

Closed

Description

@lesnik512

This was generated by AI during a pre-4.0 audit of main at 9cd88e7.

All reproduced on main (scripts were in the audit scratchpad; the repros below are the essence). Each fix starts with a failing test.

1. A finalizer that resolves from its own container creates instances that are never finalized

closed is set only after the finalizers run (container.py close_sync/close_async). A finalizer calling container.resolve(R2) re-creates R2 after it was finalized: R2 built twice, cached_count() == 1 after close. Expected: the container counts as closed during finalization (such a resolve raises ContainerClosedError). Observable behaviour change, so before 4.0.

2. A finalizer that raises leaves a stale instance that is never finalized again

CacheItem.close_* raises before self.clear() (registries/cache_registry.py:49-69), and the item is dropped from _creation_order (:91-120). After close_sync() raises FinalizerError, open() and resolve() return the same half-finalized object, and later closes never retry it. Same for close_async. Expected: clear the slot after a failed finalizer.

3. A cancelled close_async skips the remaining finalizers but marks the container closed

except Exception in cache_registry.py:91-104 lets CancelledError escape the loop; finally: self.closed = True still runs. Repro: asyncio.wait_for(c.close_async(), 0.05) with one slow async finalizer created after a sync one: closed=True, the sync finalizer never ran. Expected: remaining finalizers still run (or the items stay queued), then the cancellation propagates.

4. Overrides vs root close

Moved to #580: root close stops resetting overrides, which removes the handle-resurrection case.

Acceptance

A test per item, sync and async where applicable; lifecycle.md updated for item 1.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingready-for-agentFully specified, ready for an AFK agent

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions