Skip to content

Commit a67c029

Browse files
committed
Added: Rate limiting the requests to Notion API
1 parent 5337637 commit a67c029

3 files changed

Lines changed: 46 additions & 15 deletions

File tree

poetry.lock

Lines changed: 13 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ matplotlib = "^3.5.2"
2121
pandas = "^2.0.2"
2222
loguru = "^0.7.0"
2323
aiohttp = "^3.8.5"
24+
aiolimiter = "^1.1.0"
2425

2526
[tool.poetry.group.dev.dependencies]
2627
pycodestyle = "^2.10.0"

python_notion_api/async_api/api.py

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from typing import Any, Dict, Generator, Literal, Optional, Type
55

66
import aiohttp
7+
from aiolimiter import AsyncLimiter
78
from loguru import logger
89

910
from python_notion_api.async_api.notion_block import NotionBlock
@@ -26,10 +27,17 @@ class AsyncNotionAPI:
2627
Args:
2728
access_token: Notion access token
2829
api_version: Version of the notion API
30+
rate_limit: (number_of_requests, number of seconds). Default
31+
is set at the rate limit of Notion (3 per second), with a longer
32+
interval to allow bursts.
2933
"""
3034

3135
def __init__(
32-
self, access_token: str, api_version="2022-06-28", page_limit=20
36+
self,
37+
access_token: str,
38+
api_version="2022-06-28",
39+
page_limit=20,
40+
rate_limit=(500, 200),
3341
):
3442
self._access_token = access_token
3543
self._base_url = "https://api.notion.com/v1/"
@@ -40,6 +48,7 @@ def __init__(
4048
status_forcelist=[429, 500, 502, 503, 504, 409],
4149
)
4250
self._page_limit = page_limit
51+
self.limiter = AsyncLimiter(*rate_limit)
4352

4453
@property
4554
def request_headers(self):
@@ -104,13 +113,14 @@ async def _request_attempt(
104113
data: Data to pass to the request.
105114
params: Params to pass to the request.
106115
"""
107-
return await session.request(
108-
method=request_type,
109-
url=url,
110-
headers=self.request_headers,
111-
params=params,
112-
data=data,
113-
)
116+
async with self.limiter:
117+
return await session.request(
118+
method=request_type,
119+
url=url,
120+
headers=self.request_headers,
121+
params=params,
122+
data=data,
123+
)
114124

115125
async def _request(
116126
self,
@@ -166,12 +176,21 @@ async def _request(
166176
)
167177
raise Exception("Request failed")
168178

169-
delay = min(
170-
retry_strategy.backoff_factor * (2 ** (i)),
171-
retry_strategy.max_backoff,
172-
)
179+
if response.status == 429:
180+
delay = int(response.headers["Retry-After"])
181+
logger.warning(
182+
f"Request to {url} failed:"
183+
f"\n{response.status}"
184+
f"\nRetry-After: {delay}"
185+
f"\n{decoded_data}"
186+
)
187+
else:
188+
delay = min(
189+
retry_strategy.backoff_factor * (2 ** (i)),
190+
retry_strategy.max_backoff,
191+
)
173192

174-
logger.error(
193+
logger.warning(
175194
f"Notion is busy ({response.status})."
176195
f"Retrying ({i+1}) in {delay}s"
177196
)

0 commit comments

Comments
 (0)