fix(server): mark games abandoned on room teardown + staging leaderboard
When handle_player_leave emptied a room or handle_end_game was invoked,
the room was removed from memory without touching games_v2. Periodic
cleanup only scans in-memory rooms, so those rows were stranded as
status='active' forever — staging had 42 orphans accumulated over 5h.
- event_store.update_game_abandoned: guarded UPDATE (status='active' only)
- GameLogger.log_game_abandoned{,_async}: fire-and-forget wrapper
- handle_end_game + handle_player_leave: flip status before remove_room
- LEADERBOARD_INCLUDE_TEST_DEFAULT: env override so staging can show
soak-harness accounts by default; prod keeps them hidden
Verified on staging: 42 orphans swept on restart, soak accounts now
visible on /api/stats/leaderboard (rank 1-4).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@ from typing import Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Header, Query
|
||||
from pydantic import BaseModel
|
||||
|
||||
from config import config
|
||||
from models.user import User
|
||||
from services.stats_service import StatsService
|
||||
|
||||
@@ -159,7 +160,7 @@ async def get_leaderboard(
|
||||
metric: str = Query("wins", pattern="^(wins|win_rate|avg_score|knockouts|streak|rating)$"),
|
||||
limit: int = Query(50, ge=1, le=100),
|
||||
offset: int = Query(0, ge=0),
|
||||
include_test: bool = Query(False, description="Include soak-harness test accounts"),
|
||||
include_test: Optional[bool] = Query(None, description="Include soak-harness test accounts. Defaults to LEADERBOARD_INCLUDE_TEST_DEFAULT env (False in prod)."),
|
||||
service: StatsService = Depends(get_stats_service_dep),
|
||||
):
|
||||
"""
|
||||
@@ -173,9 +174,14 @@ async def get_leaderboard(
|
||||
- streak: Best win streak
|
||||
|
||||
Players must have 5+ games to appear on leaderboards.
|
||||
By default, soak-harness test accounts are hidden.
|
||||
Soak-harness test accounts are hidden unless include_test is passed,
|
||||
or LEADERBOARD_INCLUDE_TEST_DEFAULT is set True on the server (staging).
|
||||
"""
|
||||
entries = await service.get_leaderboard(metric, limit, offset, include_test)
|
||||
effective_include_test = (
|
||||
include_test if include_test is not None
|
||||
else config.LEADERBOARD_INCLUDE_TEST_DEFAULT
|
||||
)
|
||||
entries = await service.get_leaderboard(metric, limit, offset, effective_include_test)
|
||||
|
||||
return {
|
||||
"metric": metric,
|
||||
|
||||
Reference in New Issue
Block a user