Skip to content

Add bounded-concurrency async league ingestion - #48

Merged
Mattsface merged 2 commits into
mainfrom
issue-31/statsapi-1.1-async-ingestion
Aug 29, 2026
Merged

Add bounded-concurrency async league ingestion#48
Mattsface merged 2 commits into
mainfrom
issue-31/statsapi-1.1-async-ingestion

Conversation

@Mattsface

Copy link
Copy Markdown
Member

Why

python-mlb-statsapi 1.1.0 is now released with the public AsyncMlb client. League-season ingestion is network-bound, and prior live testing showed the async path is roughly 3x faster on average while preserving the existing SQLite persistence model.

This PR adopts the released async client without changing the browser or database architecture.

What

  • Upgrades python-mlb-statsapi to the released 1.1.0 package with the async extra.
  • Adds ingest_league_season_async alongside the existing sequential ingestion path.
  • Uses bounded concurrency across teams with one shared AsyncMlb client and connection pool.
  • Keeps each team's MLB requests ordered while allowing multiple teams to fetch concurrently.
  • Keeps SQLAlchemy synchronous and serializes persistence so there is never more than one database writer.
  • Preserves the existing short transaction boundary: fetch and normalize first, then persist batting and pitching atomically in one team-season transaction.
  • Preserves COMPLETE / INCOMPLETE coverage semantics and idempotent reruns.
  • Cancels and drains sibling ingestion tasks before propagating unexpected async failures, including exceptions raised by progress callbacks.
  • Adds --async and --concurrency options to scripts/import_league_season.py; sequential ingestion remains available as the default/reference path.
  • Adds documentation for the concurrent ingestion design and failure semantics.

Tests

Adds offline deterministic coverage for:

  • async team discovery and game-log retrieval
  • sync/async request and normalization parity
  • full persisted batting and pitching parity between sequential and async ingestion
  • bounded concurrency
  • shared async client ownership
  • serialized database writes
  • idempotent reruns
  • COMPLETE / INCOMPLETE coverage behavior
  • expected per-team failures
  • unexpected exception propagation
  • cancellation and draining of still-running sibling tasks
  • progress callback failure cleanup
  • CLI async/concurrency argument handling

Also validated with the existing full pytest and Ruff checks during development.

Risk and impact

Normal

The change introduces concurrent network orchestration and therefore adds lifecycle/error-handling complexity. The database side remains deliberately conservative: synchronous SQLAlchemy, serialized writes, and the same persistence functions and transaction boundaries as the sequential path.

If the async path fails unexpectedly, the league run remains RUNNING rather than claiming trustworthy coverage, and outstanding sibling tasks are cancelled and drained before the error escapes. Successfully committed team-seasons remain committed.

The sequential ingestion path remains available as a reference and fallback.

Closes #31

Mattsface and others added 2 commits August 28, 2026 22:20
Upgrade python-mlb-statsapi to 1.1.0 to use its released AsyncMlb client,
and add ingest_league_season_async alongside the existing sequential
ingest_league_season. Fetches for each team (schedule, hitting/pitching
logs) run concurrently up to a configurable limit while persistence stays
serialized through a shared write lock, reusing the same validation,
normalization, and persistence logic as the sync path. Exposes
--async/--concurrency on scripts/import_league_season.py.
…lure

asyncio.gather propagates the first exception without cancelling still-running
siblings, letting another team keep hitting MLB or reach persist_team_season
after the caller has already been told the run failed. Team coroutines are now
owned as explicit asyncio.Tasks so an unexpected exception (including one from
on_team_complete) cancels and drains every other task before it escapes
ingest_league_season_async.

Also strengthens the sync/async parity test to compare full persisted batting
and pitching domain objects between the two paths, rather than a handful of
batting columns.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gjqhyq4iPHf51Mr3PyHtMb
@Mattsface Mattsface self-assigned this Aug 29, 2026
@Mattsface
Mattsface merged commit 65aa1bf into main Aug 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Upgrade to python-mlb-statsapi 1.1.0 and adopt async support

1 participant