Skip to content

feat: add scope() for hierarchical child scopes#39

Open
jodinathan wants to merge 1 commit into
mintware-de:mainfrom
jodinathan:feat/child-scope
Open

feat: add scope() for hierarchical child scopes#39
jodinathan wants to merge 1 commit into
mintware-de:mainfrom
jodinathan:feat/child-scope

Conversation

@jodinathan

Copy link
Copy Markdown

Adds ServiceContainer.scope(): a child container with its OWN singleton instance cache and a parent reference. Unknown services resolve from the parent (and cache there); scope-local services passed in scope(services:) are cached only in the child, so they never leak to the parent or siblings. has() and resolveByTag() also fall back to the parent. enhance() is untouched.

Adds ServiceContainer.scope(): a child container with its OWN singleton
instance cache and a parent reference. Unknown services resolve from the
parent (and cache there); scope-local services passed in scope(services:)
are cached only in the child, so they never leak to the parent or siblings.
has() and resolveByTag() also fall back to the parent. enhance() is
untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jodinathan

Copy link
Copy Markdown
Author

@devtronic can you check this PR please

@devtronic

Copy link
Copy Markdown
Member

@devtronic can you check this PR please

Hi @jodinathan,
thanks for contributing. I'll review the code by the end of the week 🙌

@devtronic

Copy link
Copy Markdown
Member

@jodinathan Sorry, I haven't gotten around to it yet, and I'll be out of the office for the rest of the week. I'll take a look as soon as I get back.

@devtronic

Copy link
Copy Markdown
Member

@jodinathan Thanks for your patience. I spent quite some time reviewing your changes, and I think the underlying issue is architectural: we're trying to solve the wrong problem.

Singleton services always resolve to the same instance, regardless of where they are resolved. Because of that, enhance() is the preferred way to create a new scope with custom services.

What your changes are actually trying to achieve is support for scoped services, which is a feature that isn't implemented yet.

Scoped services have been on my wishlist for this project for a long time, but they're more complex than they first appear. We need to ensure that a service never depends on another service with a shorter lifetime.

Consumer ↓ / Dependency → Transient Scoped Singleton
Transient
Scoped
Singleton ⚠️

My suggestion would be:

  • Add a new ServiceLifetime.scoped.
  • Enforce the lifetime rules shown above, either during boot() or in _tryResolveInternal(). Performing the validation during boot() is more efficient because it only runs once, while _tryResolveInternal() is more robust because it also validates services registered at runtime.
  • Cache scoped service instances in a separate Map (one cache per scope).
  • When resolving, check first the scoped instances and then the _serviceInstances.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants