Syntrex Claude Sonnet 4.6 commited on
Commit
07da77f
·
1 Parent(s): 9846940

Fix QueuePool exhaustion: close leaked connections + widen pool + fix 2026 retry loop

Browse files

- _fire_completion: add finally block to always close fresh_conn, preventing
daemon threads from leaking connections that exhaust the pool
- remote_db: raise pool_size 5→10, max_overflow 10→20, pool_timeout 30→60
to tolerate burst connections during live game windows
- render_statcast_retry_fragment: exclude games in live_pitch_mix_2026 from
pending query so 2026 games no longer perpetually re-trigger _fire_completion

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (2) hide show
  1. app.py +11 -0
  2. database/remote_db.py +3 -0
app.py CHANGED
@@ -403,12 +403,19 @@ def _fire_completion(pk_str: str, game_date: str, scores_df: pd.DataFrame) -> No
403
  scores_snapshot = scores_df.copy()
404
 
405
  def _run() -> None:
 
406
  try:
407
  from database.db import get_connection as _get_conn
408
  fresh_conn = _get_conn()
409
  on_game_complete(fresh_conn, int(pk_str), game_date, scores_snapshot)
410
  except Exception as exc:
411
  logger.warning("[_fire_completion] thread error game_pk=%s: %s", pk_str, exc)
 
 
 
 
 
 
412
 
413
  t = threading.Thread(target=_run, daemon=True)
414
  t.start()
@@ -475,6 +482,10 @@ def render_statcast_retry_fragment() -> None:
475
  SELECT 1 FROM statcast_event_core s
476
  WHERE s.game_pk = g.game_pk::BIGINT
477
  )
 
 
 
 
478
  ORDER BY g.graded_at DESC
479
  LIMIT 10
480
  """),
 
403
  scores_snapshot = scores_df.copy()
404
 
405
  def _run() -> None:
406
+ fresh_conn = None
407
  try:
408
  from database.db import get_connection as _get_conn
409
  fresh_conn = _get_conn()
410
  on_game_complete(fresh_conn, int(pk_str), game_date, scores_snapshot)
411
  except Exception as exc:
412
  logger.warning("[_fire_completion] thread error game_pk=%s: %s", pk_str, exc)
413
+ finally:
414
+ if fresh_conn is not None:
415
+ try:
416
+ fresh_conn.close()
417
+ except Exception:
418
+ pass
419
 
420
  t = threading.Thread(target=_run, daemon=True)
421
  t.start()
 
482
  SELECT 1 FROM statcast_event_core s
483
  WHERE s.game_pk = g.game_pk::BIGINT
484
  )
485
+ AND NOT EXISTS (
486
+ SELECT 1 FROM live_pitch_mix_2026 lpm
487
+ WHERE lpm.game_pk = g.game_pk::BIGINT
488
+ )
489
  ORDER BY g.graded_at DESC
490
  LIMIT 10
491
  """),
database/remote_db.py CHANGED
@@ -29,6 +29,9 @@ def _get_engine():
29
 
30
  _engine = create_engine(
31
  database_url,
 
 
 
32
  pool_pre_ping=True,
33
  pool_recycle=300,
34
  )
 
29
 
30
  _engine = create_engine(
31
  database_url,
32
+ pool_size=10,
33
+ max_overflow=20,
34
+ pool_timeout=60,
35
  pool_pre_ping=True,
36
  pool_recycle=300,
37
  )