Emit lifecycle events when async_become_ready() follows not-ready instantiation
- Dominant language
- Python
- Stars
- 11
- Forks
- 8
- Avg merge
- 9h 26m
- Merged PRs (30d)
- 6
Description
## Summary
When an `AsyncInjectable` is first instantiated with a not-ready key and later brought to ready with `async_become_ready()`, the second transition does not emit an injector lifecycle event. This leaves event-driven instrumentation—particularly `carthage.entanglement.instrumentation`—without a notification that the provider has moved from `not_ready` to `ready`.
## Current behavior
A typical sequence is:
1. Resolve `InjectionKey(SomeType, _ready=False)`.
2. The original `InstantiationContext` emits `dependency_final`; entanglement records the provider as `InstantiationProgress.not_ready`.
3. Later, call `obj.async_become_ready()` directly.
4. `AsyncInjectable.async_become_ready()` enters an `AsyncBecomeReadyContext`, runs the dependency/ready protocol, and reaches `ReadyState.READY`.
5. When this is a root-level call, `AsyncBecomeReadyContext` has no parent to notify and does not emit `dependency_progress` or `dependency_final` through the injector.
`CarthageRegistry.instrument_injector()` listens for `dependency_progress` and `dependency_final` to update `ProviderInfo` and invoke registered entanglement instrumentation callbacks. Because neither event is emitted for this path, the synchronized state can remain `not_ready` indefinitely.
## Expected behavior
An observable ready transition initiated by `async_become_ready()` should produce the same useful lifecycle notification as a ready transition performed during dependency instantiation:
- instrumentation can observe that work has started;
- successful completion publishes the provider as ready;
- the event is dispatched to the provider's applicable injection keys and the `InjectionKey(Injector)` wildcard;
- callbacks receive an inspector/context from which the existing provider identity and current value can be recovered.
The implementation should avoid duplicate terminal events when `async_become_ready()` is already nested inside an `InstantiationContext`, and concurrent callers waiting on the same `_ready_future` should not report multiple independent transitions.
## Suggested regression test
1. Register an `AsyncInjectable` whose `async_ready()` is nontrivial.
2. Instantiate it using `InjectionKey(Type, _ready=False)`.
3. Attach listeners for `dependency_progress` and `dependency_final` (or instrument a `CarthageRegistry`).
4. Call `obj.async_become_ready()` outside the original instantiation context.
5. Assert that the ready transition is observed and `ProviderInfo.state` becomes `InstantiationProgress.ready`.
6. Also cover the normal ready-at-instantiation path and two concurrent `async_become_ready()` callers to ensure events are not duplicated.
Failure/cancellation should leave the object in its existing retryable state and should not publish a false ready state.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.