channable / opnieuw

One weird trick to make your code more reliable
https://tech.channable.com/posts/2020-02-05-opnieuw.html
BSD 3-Clause "New" or "Revised" License
289 stars 11 forks source link

Support for callbacks #12

Closed michaeloliverx closed 4 years ago

michaeloliverx commented 4 years ago

It would be nice to have support for a callback (sync or async) which is called once the retry limit was reached.

Btw thanks for the library

ReinierMaas commented 4 years ago

The last thrown exception is raised once the retry window is over or the maximum number of retries is reached.

https://github.com/channable/opnieuw/blob/480142dc0676841ef92e2f437bf92179f5c696c2/opnieuw/retries.py#L247-L248

You could create a decorator that catches the exceptions you would like your callback to handle. The new decorator, for simplicity named add_callback, should be the outside the retry decorator if you want to retry the exception and only handle unresolved exceptions in your callback. The add_callback decorator should be inside the retry decorator if you like to handle each of the exceptions before retrying.

def add_callback(
    *,
    callback_on_exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]],
    callback: Callable[Union[Type[Exception], Tuple[Type[Exception], ...]], Any],
) -> Callable[[F], F]:
    def decorator(f: F) -> F:
        @functools.wraps(f)
        def wrapper(*args: Any, **kwargs: Any) -> Any:
            try:
                return f(*args, **kwargs)
            except callback_on_exceptions as e:
                callback(e)
                raise e
        return cast(F, wrapper)
    return decorator

Thanks for using our library! Hopefully, this helps to handle the problems you encounter.