Как реализовать отложенный callback для корутины?
Подскажите, как реализовать callback для coroutine?
Минимально-рабочая конструкция, которой удалось достичь
def ratelimit(fn, max_limit=1, timeout=2):
ctx = contextvars.ContextVar(
'ratelimit-semaphore',
default=asyncio.Semaphore(max_limit)
)
def callback(a, sem):
async def _():
await asyncio.sleep(timeout)
sem.release()
current_loop = asyncio.get_running_loop()
current_loop.create_task(_())
def _():
async def wrapper(*args, **kwargs):
loop = kwargs.get('loop', asyncio.get_running_loop())
assert isinstance(loop, asyncio.AbstractEventLoop)
sem = ctx.get()
await sem.acquire()
task = loop.create_task(fn(*args, **kwargs), name=repr(fn.__name__))
task.add_done_callback(functools.partial(callback, sem=sem))
return await task
return wrapper
return _()
Увы, если loop был завершен - вызов коллбека не происходит