-
Notifications
You must be signed in to change notification settings - Fork 12
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
feature request: singleton for coroutine functions #114
Comments
Resource can be used and async generator instead of coroutine |
@lesnik512 , if client has coroutine function in other module and wants to use a result as singleton - he needs to add extra code to put it into Resource and then use as singleton: from my_app.my_module import create_my_obj_async, MyObj
async def _init_my_obj(arg1: str, arg2: int, ...) -> AsyncIterator[MyObj]:
yield await create_my_obj_async(arg1, arg2, ...)
class DIContainer(BaseContainer):
async_obj = providers.Resource(_init_my_obj) In my opinion, Singleton can handle async coroutine and client won't need to write extra code. |
There are two options I can think of:
|
I'm ok with 1 option. Just for note, in the second we can first check for coroutine function Callable[..., Awaitable[T_co]] and use awaits during resolving. If it's not coroutine function then it's a regular function Callable[..., T_co] - use regular calls without awaits. Type |
as a matter of fact it does. At least, I haven't found a way to work it together in one union type. Before we start to implement this can you please provide a real-life example of when an async singleton might be useful? |
I believe it is important to only add new features if they are truly necessary and do not introduce unnecessary complexity or hacks into the codebase. |
I can share a part of code, so here is async contstructor for a sender class MySender:
@classmethod
async def create(cls, manager, config) -> MySender:
factory = manager.get_sender_factory()
return cls(
sender=await factory.create_sender(...)
)
def __init__(self, sender):
self.__sender = sender
async def send(self, ...):
await self.__sender.send(...) The idea is to use a single instance of that publisher on demand in the application. For now it's not possible, so AsyncFactory is used as provider. class DIContainer:
# ...
my_sender = providers.AsyncFactory(MySender.create, ...) I pretty sure that anything that can be put into Factory provider, can be also put into Singleton provider . Also, the idea of the library is to support async by default. |
Don't you need to tear down sender at the end? Seems like sender is needed to be moved to Resource |
And why is sender created asynchronously? What's happening inside create_sender? |
Sender uses aio pika channel and requires initialized channel for work. Channel initialization is done via |
@zerlok Can you, please share the code of |
somthing like this async def create_sender(
self,
# ...
) -> Sender:
factory = PublisherFactory(
channel_factory=self.__channel_factory,
# params ...
)
publisher = await factory.create_publisher(...)
return Sender(
publisher=publisher,
# ...
)
async def create_publisher(
self,
# ...
) -> Publisher:
channel = await self.__channel_factory.create_channel(...)
exchange = await channel.declare_exchange(...)
return Publisher(
connection=self.__connection,
exchange=exchange,
# ...
)
async def create_channel(
self,
# ...
) -> aio_pika.Channel:
impl = self.__get_connection()
assert isinstance(impl, aio_pika.Connection)
channel = await impl.channel(...)
assert isinstance(channel, aio_pika.Channel)
# ...
return channel |
@zerlok I agree, could be useful. |
Singleton
provider expects only synchronous callable object. I think it would be great to support coroutine functions too.At the moment the following code raises not awaited warning & obj1 is not
MyObj
instance.Output:
The text was updated successfully, but these errors were encountered: