perf: N+1 sequential API calls in schedule_service (up to 18 per request) #88

Closed
opened 2026-03-20 13:17:00 +00:00 by cal · 1 comment
Owner

Problem

schedule_service.py fetches game data one week at a time in a loop, issuing up to 18 sequential HTTP requests.

get_team_schedule() lines 84–121

for week in week_range:
    week_games = await self.get_week_schedule(season, week)

For a full-season view with no weeks argument, this fires 18 sequential HTTP requests.

get_recent_games() lines 123–158

Loops over 2 weeks sequentially.

get_upcoming_games() lines 160–196

Loops over up to 18 weeks sequentially with early-exit heuristic.

Fix

Option A: Use asyncio.gather() across all week fetches:

results = await asyncio.gather(*[
    self.get_week_schedule(season, week) for week in week_range
])

Option B (better): Add a single API endpoint/param that returns games filtered by team across all weeks, eliminating the per-week loop entirely.

Impact

HIGH/schedule is a common user command. 18 serial round-trips at ~100ms each = ~1.8 seconds of avoidable latency.

## Problem `schedule_service.py` fetches game data one week at a time in a loop, issuing up to 18 sequential HTTP requests. ### `get_team_schedule()` lines 84–121 ```python for week in week_range: week_games = await self.get_week_schedule(season, week) ``` For a full-season view with no `weeks` argument, this fires **18 sequential HTTP requests**. ### `get_recent_games()` lines 123–158 Loops over 2 weeks sequentially. ### `get_upcoming_games()` lines 160–196 Loops over up to 18 weeks sequentially with early-exit heuristic. ## Fix Option A: Use `asyncio.gather()` across all week fetches: ```python results = await asyncio.gather(*[ self.get_week_schedule(season, week) for week in week_range ]) ``` Option B (better): Add a single API endpoint/param that returns games filtered by team across all weeks, eliminating the per-week loop entirely. ## Impact **HIGH** — `/schedule` is a common user command. 18 serial round-trips at ~100ms each = ~1.8 seconds of avoidable latency.
cal added the
ai-working
label 2026-03-20 13:18:35 +00:00
cal removed the
ai-working
label 2026-03-20 13:21:31 +00:00
Claude added the
ai-working
label 2026-03-20 15:01:11 +00:00
Claude added the
status/pr-open
label 2026-03-20 15:02:40 +00:00
Collaborator

PR #103 opened: #103

Replaced all three sequential week-fetch loops with asyncio.gather()get_team_schedule(), get_recent_games(), and get_upcoming_games(). Also added the missing import asyncio. 16 new tests added covering the parallelization behavior.

PR #103 opened: https://git.manticorum.com/cal/major-domo-v2/pulls/103 Replaced all three sequential week-fetch loops with `asyncio.gather()` — `get_team_schedule()`, `get_recent_games()`, and `get_upcoming_games()`. Also added the missing `import asyncio`. 16 new tests added covering the parallelization behavior.
Claude added
ai-pr-opened
and removed
ai-working
labels 2026-03-20 15:02:49 +00:00
cal closed this issue 2026-03-20 15:16:42 +00:00
Sign in to join this conversation.
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: cal/major-domo-v2#88
No description provided.