oettaM123 Claude Opus 4.8 commited on
Commit
a2af882
·
1 Parent(s): d550346

lb-autoheal: take the daily history snapshot under the leaderboard lock

Browse files

_sm_lb_keep_history_fresh() iterated the 1.6M-row players dict via
_sm_leaderboard_snapshot_daily WITHOUT the lock, so a concurrent ingest
could raise "dict changed size during iteration" and skip that day's
snapshot. Hold _SM_LEADERBOARD_LOCK across the daily snapshot (the hourly
one still runs outside it -- it takes the lock itself). Cheap: the daily
does real work only once/day, a file-exists check otherwise.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files changed (1) hide show
  1. app.py +2 -2
app.py CHANGED
@@ -12651,10 +12651,10 @@ def _sm_lb_keep_history_fresh():
12651
  snapshots here so A always holds fresh bootstrap history. Once/hour + once/day of real work;
12652
  a file-exists check otherwise."""
12653
  try:
12654
- _sm_leaderboard_snapshot_hourly()
12655
  with _SM_LEADERBOARD_LOCK:
12656
  state = _sm_leaderboard_load_unlocked()
12657
- _sm_leaderboard_snapshot_daily(state)
12658
  except Exception as exc: # noqa: BLE001
12659
  print(f"[lb-autoheal] snapshot keep-fresh: {type(exc).__name__}: {str(exc)[:120]}")
12660
 
 
12651
  snapshots here so A always holds fresh bootstrap history. Once/hour + once/day of real work;
12652
  a file-exists check otherwise."""
12653
  try:
12654
+ _sm_leaderboard_snapshot_hourly() # acquires the lock itself -> call it OUTSIDE the lock
12655
  with _SM_LEADERBOARD_LOCK:
12656
  state = _sm_leaderboard_load_unlocked()
12657
+ _sm_leaderboard_snapshot_daily(state) # iterate players under the lock (no mid-iter mutation)
12658
  except Exception as exc: # noqa: BLE001
12659
  print(f"[lb-autoheal] snapshot keep-fresh: {type(exc).__name__}: {str(exc)[:120]}")
12660