Progress bar + minor bugfix
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import asyncio
|
||||
import concurrent.futures
|
||||
import functools
|
||||
import inspect
|
||||
import sys
|
||||
import time
|
||||
import typing
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import Any, AsyncGenerator, Callable, Iterator, List, Optional, Set, TypeVar, cast
|
||||
|
||||
import synchronicity
|
||||
from typing_extensions import ParamSpec
|
||||
|
||||
|
||||
synchronizer = synchronicity.Synchronizer()
|
||||
|
||||
def synchronize_api(obj, target_module=None):
|
||||
if inspect.isclass(obj):
|
||||
blocking_name = obj.__name__.lstrip("_")
|
||||
elif inspect.isfunction(object):
|
||||
blocking_name = obj.__name__.lstrip("_")
|
||||
elif isinstance(obj, TypeVar):
|
||||
blocking_name = "_BLOCKING_" + obj.__name__
|
||||
else:
|
||||
blocking_name = None
|
||||
if target_module is None:
|
||||
target_module = obj.__module__
|
||||
return synchronizer.create_blocking(obj, blocking_name, target_module=target_module)
|
||||
|
||||
def retry(direct_fn=None, *, n_attempts=3, base_delay=0, delay_factor=2, timeout=90):
|
||||
"""Decorator that calls an async function multiple times, with a given timeout.
|
||||
|
||||
If a `base_delay` is provided, the function is given an exponentially
|
||||
increasing delay on each run, up until the maximum number of attempts.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
@retry
|
||||
async def may_fail_default():
|
||||
# ...
|
||||
pass
|
||||
|
||||
@retry(n_attempts=5, base_delay=1)
|
||||
async def may_fail_delay():
|
||||
# ...
|
||||
pass
|
||||
```
|
||||
"""
|
||||
|
||||
def decorator(fn):
|
||||
@functools.wraps(fn)
|
||||
async def f_wrapped(*args, **kwargs):
|
||||
delay = base_delay
|
||||
for i in range(n_attempts):
|
||||
t0 = time.time()
|
||||
try:
|
||||
return await asyncio.wait_for(fn(*args, **kwargs), timeout=timeout)
|
||||
except asyncio.CancelledError:
|
||||
logger.debug(f"Function {fn} was cancelled")
|
||||
raise
|
||||
except Exception as e:
|
||||
if i >= n_attempts - 1:
|
||||
raise
|
||||
logger.debug(
|
||||
f"Failed invoking function {fn}: {e}"
|
||||
f" (took {time.time() - t0}s, sleeping {delay}s"
|
||||
f" and trying {n_attempts - i - 1} more times)"
|
||||
)
|
||||
await asyncio.sleep(delay)
|
||||
delay *= delay_factor
|
||||
|
||||
return f_wrapped
|
||||
|
||||
if direct_fn is not None:
|
||||
# It's invoked like @retry
|
||||
return decorator(direct_fn)
|
||||
else:
|
||||
# It's invoked like @retry(n_attempts=...)
|
||||
return decorator
|
||||
|
||||
Reference in New Issue
Block a user