-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdecorators.py
More file actions
67 lines (56 loc) · 2.05 KB
/
Copy pathdecorators.py
File metadata and controls
67 lines (56 loc) · 2.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
"""Decorators for enhancing Notion API client functionality."""
import asyncio
import logging
from collections.abc import Callable, Coroutine
from functools import wraps
from typing import Any
from app.core.integrations.notion.exceptions import (
NotionRateLimitError,
NotionServiceUnavailableError,
)
# * Configure logging
logger = logging.getLogger(__name__)
def retry(
max_retries: int = 3,
initial_delay: float = 1.0,
backoff_factor: float = 2.0,
) -> Callable[..., Callable[..., Coroutine[Any, Any, Any]]]:
"""
A decorator to retry an async function with exponential backoff.
Args:
max_retries: The maximum number of retries.
initial_delay: The initial delay between retries in seconds.
backoff_factor: The factor by which the delay increases each retry.
Returns:
A decorated coroutine function.
"""
def decorator(func: Callable[..., Coroutine[Any, Any, Any]]):
@wraps(func)
async def wrapper(*args: Any, **kwargs: Any) -> Any:
delay = initial_delay
for attempt in range(max_retries + 1):
try:
return await func(*args, **kwargs)
except (
NotionRateLimitError,
NotionServiceUnavailableError,
asyncio.TimeoutError,
) as e:
if attempt == max_retries:
logger.error(
"Function %s failed after %d retries.",
func.__name__,
max_retries,
)
raise e
logger.warning(
"Attempt %d/%d failed for %s. Retrying in %.2f seconds...",
attempt + 1,
max_retries,
func.__name__,
delay,
)
await asyncio.sleep(delay)
delay *= backoff_factor
return wrapper
return decorator