Implement injections in thread-local and thread-safe singleton providers

This commit is contained in:
Roman Mogylatov 2020-12-15 21:07:20 -05:00
parent 6020c6caf4
commit 90a6cb3c6d
4 changed files with 5021 additions and 3758 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -141,11 +141,11 @@ cdef class FactoryAggregate(Provider):
# Singleton providers
cdef class BaseSingleton(Provider):
cdef Factory __instantiator
cdef object __storage
cdef bint __async
cdef class Singleton(BaseSingleton):
cdef object __storage
cpdef object _provide(self, tuple args, dict kwargs)
@ -155,7 +155,6 @@ cdef class DelegatedSingleton(Singleton):
cdef class ThreadSafeSingleton(BaseSingleton):
cdef object __storage
cdef object __storage_lock
cpdef object _provide(self, tuple args, dict kwargs)
@ -166,7 +165,6 @@ cdef class DelegatedThreadSafeSingleton(ThreadSafeSingleton):
cdef class ThreadLocalSingleton(BaseSingleton):
cdef object __storage
cpdef object _provide(self, tuple args, dict kwargs)

View File

@ -2077,6 +2077,12 @@ cdef class BaseSingleton(Provider):
"""
raise NotImplementedError()
def _async_init_instance(self, future_result, result):
instance = result.result()
self.__storage = instance
self.__async = True
future_result.set_result(instance)
cdef class Singleton(BaseSingleton):
"""Singleton provider returns same instance on every call.
@ -2124,6 +2130,8 @@ cdef class Singleton(BaseSingleton):
:rtype: None
"""
if __isawaitable(self.__storage):
asyncio.ensure_future(self.__storage).cancel()
self.__storage = None
cpdef object _provide(self, tuple args, dict kwargs):
@ -2147,12 +2155,6 @@ cdef class Singleton(BaseSingleton):
return self.__storage
def _async_init_instance(self, future_result, result):
instance = result.result()
self.__storage = instance
self.__async = True
future_result.set_result(instance)
cdef class DelegatedSingleton(Singleton):
"""Delegated singleton is injected "as is".
@ -2201,18 +2203,35 @@ cdef class ThreadSafeSingleton(BaseSingleton):
:rtype: None
"""
with self.__storage_lock:
if __isawaitable(self.__storage):
asyncio.ensure_future(self.__storage).cancel()
self.__storage = None
cpdef object _provide(self, tuple args, dict kwargs):
"""Return single instance."""
storage = self.__storage
if storage is None:
instance = self.__storage
if instance is None:
with self.__storage_lock:
if self.__storage is None:
self.__storage = __factory_call(self.__instantiator,
args, kwargs)
storage = self.__storage
return storage
instance = __factory_call(self.__instantiator, args, kwargs)
if __isawaitable(instance):
future_result = asyncio.Future()
instance = asyncio.ensure_future(instance)
instance.add_done_callback(functools.partial(self._async_init_instance, future_result))
self.__storage = future_result
return future_result
self.__storage = instance
if self.__async:
result = asyncio.Future()
result.set_result(instance)
return result
return instance
cdef class DelegatedThreadSafeSingleton(ThreadSafeSingleton):
@ -2270,6 +2289,8 @@ cdef class ThreadLocalSingleton(BaseSingleton):
:rtype: None
"""
if __isawaitable(self.__storage.instance):
asyncio.ensure_future(self.__storage.instance).cancel()
del self.__storage.instance
cpdef object _provide(self, tuple args, dict kwargs):
@ -2280,10 +2301,28 @@ cdef class ThreadLocalSingleton(BaseSingleton):
instance = self.__storage.instance
except AttributeError:
instance = __factory_call(self.__instantiator, args, kwargs)
if __isawaitable(instance):
future_result = asyncio.Future()
instance = asyncio.ensure_future(instance)
instance.add_done_callback(functools.partial(self._async_init_instance, future_result))
self.__storage.instance = future_result
return future_result
self.__storage.instance = instance
finally:
if self.__async:
result = asyncio.Future()
result.set_result(instance)
return result
return instance
def _async_init_instance(self, future_result, result):
instance = result.result()
self.__storage.instance = instance
self.__async = True
future_result.set_result(instance)
cdef class DelegatedThreadLocalSingleton(ThreadLocalSingleton):
"""Delegated thread-local singleton is injected "as is".