injector icon indicating copy to clipboard operation
injector copied to clipboard

[Discussion] Entering/Existing Scopes?

Open Enforcer opened this issue 5 years ago • 3 comments

Hi, let me start from thanking for the awesome project 🎉

Recently I was implementing a custom scope and I noticed a need for explicitly demarking beginning and ending of this scope. Mine was similar to flask_injector's RequestScope but could also be used outside web framework context, i.e. in background jobs or CLI commands.

I know injector is heavily inspired by Guice and I noticed in their documentation that their API supports enter and exit methods.

I'd like to start a brainstorming about this concept to either:

  • introduce a new API for entering/exiting a scope - similar to configure, provide empty enter, exit methods to be overriden,
  • expand documentation to give others tips to implement such a thing on their own,
  • other?

BTW, here's my custom scope implementation: https://github.com/Enforcer/clean-architecture/blob/master/auctioning_platform/main/main/modules.py#L21 Basically, it's a copy-pasted ThreadLocalScope with extras.

Enforcer avatar Oct 17 '20 22:10 Enforcer

Hey, thank you for the kind words, I'm happy you found the project useful. I don't have any specifics in mind at this point but yes, the whole scope entering/exiting concept seems rather useful and desired, I'll give it some thinking.

jstasiak avatar Oct 22 '20 21:10 jstasiak

I think this ticket is a great opportunity to collect knowledge about the cases.

It's needless to say that it's great to have this small and easy to understand library. An easy and pragmatic approach may not be the simplest to maintain in the future.

I was thinking too what that life-cycle of the dependency is. And looks like it's very dependent on the usage context of the dependency. The integration point of the injector with the usage context is the right place to define what the life-cycle is and what to trigger life-cycle methods on the dependencies.

I had one case when I needed to close resources at the end of the request in nameko-injector integration.

The first problem for me was to declare what's the protocol that determines life-cycle of the dependency. I can think about close method. enter is a dependency creation by a provider.

Following interface-segregation principle we probably need many. Closable dependency, timeout-aware dependency etc.

After that we need to create a new scope that understands the protocols and provides API to fan out protocol call on all the dependencies. In my case I decided to not even have such method on the scope as I wanted to decide rules of error handling outside (in middleware)

This library has great documentation that helped me many times. Maybe the first step is to write a new section about custom scopes, life-cycle management in terms of good practices.

signalpillar avatar Nov 15 '20 13:11 signalpillar

Hmm, I'm coming across the same problem right as we speak.. You mentioned middleware, and I think that might indeed be the right layer of abstraction for a generic scope layer, i.e. something that initializes, calls next(), and so on, until the scope is disposed and we follow the chain in reverse:

TContext = TypeVar("TContext")

# These get chained by each exposing a `call_next`
Delegate = Callable[[TContext, "Delegate"], Union[Any, Awaitable[Any]]]

Maybe it's overthinking it, but you do have a point that there's a ton of cases to consider and this would be the most general approach.

Check out https://github.com/robdmc/consecution/tree/master

JosXa avatar Dec 05 '20 19:12 JosXa