Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Singletons for AsyncIO #105

Open
Gr1N opened this issue Jun 27, 2024 · 4 comments
Open

Singletons for AsyncIO #105

Gr1N opened this issue Jun 27, 2024 · 4 comments

Comments

@Gr1N
Copy link

Gr1N commented Jun 27, 2024

Hey!

First of all, thank you for the library; I love the simplicity of the design and how it can be easily used in projects.

However, it seems impossible to have singletons for AsyncIO components. Yes, we can have them as providers and async context managers, as it stated in the examples:

@contextlib.asynccontextmanager
async def get_conn_async():
    obj = MockConnection()
    await obj.connect()
    yield obj
    await obj.destroy()

def config(binder):
    binder.bind_to_provider(MockConnection, get_conn_sync)

inject.configure(config)

@inject.autoparams()
def example(conn: MockConnection):
    # Connection and file will be automatically destroyed on exit.
    pass

It can be a good approach for simple cases, but I don't want to open database connections each time I call some function. Of course, because of the nature of AsyncIO, I think you stuck to this design, and probably without something like await inject.wait_shutdown() with manual control, we can't achieve singletons.

Nevertheless, maybe I'm missing something. Is it possible to inject a single database connection without any additional magic?

@ivankorobkov
Copy link
Owner

Hi!

I think this is application/database specific actually and have little to do with inject. Yet, maybe I am wrong.

@ivankorobkov
Copy link
Owner

Could you give some examples what you are trying to achieve?

@Gr1N
Copy link
Author

Gr1N commented Jul 1, 2024

Yep, sure.

Imagine we develop a basic web application. In most cases, we need connections to PostgreSQL, Redis, and Kafka (put more of them here). And we may want to inject them at various levels of our application. The good part is that the inject library may help with injection functionality, which is pretty useful.

However, regarding the AsyncIO application, we need to focus on two additional aspects of our connections: how to start and shut them down. The best way to do that is to incorporate such logic into the application lifecycle, start them once on application startup, provide singletons to use in any part of the application, and then gracefully stop them during application shutdown.

With the current implementation of the library, I see only two potential solutions:

  • I can use .bind_to_provider(). It can work for simple cases, but it is expensive, for example, for a database connection to open and close them each time I inject a client into a function or method.
  • I can use .bind() only and provide some additional logic on top of the library to handle the application's lifecycle and start and shut down logic.

I think it would be great to have such logic out of the box to cover the application's lifecycle for AsyncIO components.

@ivankorobkov
Copy link
Owner

The best way to do that is to incorporate such logic into the application lifecycle, start them once on application startup

Inject is specifically designed as a simple minimalistic DI-framework, not an application framework. You could build your own app with a custom lifecycle using it.

I can use .bind_to_provider(). It can work for simple cases, but it is expensive, for example, for a database connection to open and close them each time I inject a client into a function or method.

You could use a connection pool and get/release a connection each time.

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

No branches or pull requests

2 participants