API allows unbounded queries causing Gunicorn worker timeouts #98
Labels
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: cal/major-domo-database#98
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Gunicorn workers are repeatedly timing out (120s) and getting SIGABRT'd — 12 occurrences in the last 2 days. The monitoring stack detects the unhealthy window during worker recycling and restarts the container.
Root Cause
Requests arriving with
limit=99999or empty required filter parameters cause the API to attempt returning enormous result sets, tying up workers past the timeout threshold.Source: External clients via reverse proxy
UPDATED: The source IP
172.25.0.3is nginx-proxy-manager, NOT the Discord bot. These queries come from external clients (website users or direct API callers) through the reverse proxy. The Discord bot (172.18.0.2) is on a separate Docker network and does not generate these queries.Observed bad requests (from container logs)
GET /plays/?limit=99999&game_id=&short_output=FALSE→ 500game_id= fetch ALL playsGET /plays/?game_id=&pitcher_id=&sort=oldest→ 500GET /players?season=9&team_id=&team_id=391→ 500team_idparamsGET /plays/batting?limit=99999&...GET /transactions?limit=99999&...Current State of the API
/players/searchhas a max limit cap (le=50). Every other endpoint trusts the client.game_id=as[''], which passesif param is not Nonechecks but generates wasteful queries./transactionshas no limit parameter at all — always returns all matching rows with recursive serialization.model_to_dict(recurse=True)amplifies the problem — each row triggers additional DB lookups for FK relations.Proposed Fix
Priority 1 — Immediate (stop the crashes)
MAX_LIMITconstant (e.g., 500) and enforcele=500across all list endpoints['']toNonevia a shared dependencylimitparam to/transactionswith default=200, max=500Priority 2 — Short-term hardening
statement_timeout = 30sas a safety net below the Gunicorn timeoutshort_output=Truewhen limit > 100 to prevent recursive serialization on large result setsPriority 3 — Architectural
PaginationParamsdependency across all list endpointsImpact