Skip to content

Commit 1d3acc4

Browse files
committed
perf(http): Shift from requests to asyncio/aiohttp
We have better performance switching to aiohttp.
1 parent 5cd1375 commit 1d3acc4

File tree

3 files changed

+39
-21
lines changed

3 files changed

+39
-21
lines changed

my_chess_style/settings/base.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,9 @@
141141
celery_pass = os.getenv("RABBITMQ_DEFAULT_PASS")
142142
net_host = os.getenv("DB_HOST")
143143

144+
REDIS_URI = f"redis://:{os.getenv('CACHE_PASSWORD')}@{os.getenv('DB_HOST')}:6379/0"
144145
CELERY_BROKER_URL = f"amqp://{celery_user}:{celery_pass}@{net_host}:5672/"
145-
CELERY_RESULT_BACKEND = (
146-
f"redis://:{os.getenv('CACHE_PASSWORD')}@{os.getenv('DB_HOST')}:6379/0"
147-
)
146+
CELERY_RESULT_BACKEND = REDIS_URI
148147
CELERY_RESULT_SERIALIZER = "json"
149148
CELERY_ACCEPT_CONTENT = ["json", "pickle"]
150149
CELERY_RESULT_ACCEPT_CONTENT = ["json", "pickle"]

style_predictor/apis/pgn/utils.py

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
import asyncio
12
import logging
23
import os
3-
import time
44

5+
import aiohttp
56
import berserk
6-
import requests
77
from chessdotcom import ChessDotComClient
88
from dotenv import load_dotenv
99

@@ -85,7 +85,28 @@ def does_chess_dot_com_player_exists(username: str):
8585
return True
8686

8787

88-
def get_chess_dot_com_games(username: str) -> str:
88+
async def fetch_archive(
89+
archive_url: str, session: aiohttp.ClientSession, semaphore: asyncio.Semaphore
90+
):
91+
async with semaphore:
92+
while True:
93+
async with session.get(f"{archive_url}/pgn") as resp:
94+
if resp.status == 429:
95+
retry_after = resp.headers.get("Retry-After")
96+
if retry_after:
97+
LOG.info(f"Rate limited. Retrying after {retry_after} seconds.")
98+
await asyncio.sleep(int(retry_after))
99+
else:
100+
# Implement exponential backoff here if no Retry-After
101+
await asyncio.sleep(45) # Example fixed delay
102+
elif resp.status == 200:
103+
return await resp.text()
104+
else:
105+
LOG.error(f"Failed to fetch {archive_url}: {resp.status}")
106+
return ""
107+
108+
109+
async def get_chess_dot_com_games(username: str) -> str:
89110
"""Get all games of `username` from chess.com platform.
90111
91112
Args:
@@ -94,19 +115,16 @@ def get_chess_dot_com_games(username: str) -> str:
94115
Returns:
95116
string of all games.
96117
"""
97-
all_pgns: str = ""
118+
conn_limit = 15
119+
semaphore = asyncio.Semaphore(conn_limit)
120+
all_pgns: list[str] = []
98121
response = chessdotcomClient.get_player_game_archives(username)
99122
archives: dict[str, list[str]] = response.json
100-
for archive in archives.get("archives", []):
101-
resp = requests.get(f"{archive}/pgn", headers=headers, timeout=60)
102-
if resp.status_code == 200:
103-
all_pgns += f"{resp.text}\n\n"
104-
elif resp.status_code == 429:
105-
LOG.warning(f"Rate limiting encountered for {archive}")
106-
time.sleep(45)
107-
resp = requests.get(f"{archive}/pgn", headers=headers, timeout=60)
108-
if resp.status_code == 200:
109-
all_pgns += f"{resp.text}\n\n"
110-
else:
111-
LOG.error(f"Failed to fetch url {archive}/pgn")
112-
return all_pgns
123+
connection = aiohttp.TCPConnector(limit=conn_limit)
124+
async with aiohttp.ClientSession(connector=connection) as session:
125+
tasks = [
126+
fetch_archive(archive, session, semaphore)
127+
for archive in archives.get("archives", [])
128+
]
129+
all_pgns = await asyncio.gather(*tasks)
130+
return "\n\n".join(all_pgns)

style_predictor/tasks.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import asyncio
12
import logging
23
from collections import Counter, defaultdict
34
from dataclasses import dataclass
@@ -311,7 +312,7 @@ def pgn_get_games_from_file(session_id: UUID, usernames: str, pgn_data: str):
311312
@shared_task(name=constants.GET_CHESS_COM_TASK)
312313
def pgn_get_chess_com_games_by_user(session_id: UUID, username: str):
313314
"""Celery task to get chess games for user from chess.com."""
314-
pgn_data: str = get_chess_dot_com_games(username)
315+
pgn_data: str = asyncio.run(get_chess_dot_com_games(username))
315316
return save_file_and_queue_task(
316317
session_id, username, pgn_data, FileSource.CHESSDOTCOM
317318
)

0 commit comments

Comments
 (0)