Add CPU profile cleanup on shutdown and debug endpoints

- Reset all CPU profiles on server shutdown to prevent stuck profiles
- Clean up all rooms during shutdown
- Add GET /api/debug/cpu-profiles to check allocation status
- Add POST /api/debug/reset-cpu-profiles for emergency cleanup

This fixes the issue where CPU profiles get "stuck" when connections
drop without clean teardown, preventing new games from adding CPUs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Aaron D. Lee 2026-01-27 19:08:14 -05:00
parent 15135c404e
commit 724bf87c43

View File

@ -15,7 +15,7 @@ import redis.asyncio as redis
from config import config
from room import RoomManager, Room
from game import GamePhase, GameOptions
from ai import GolfAI, process_cpu_turn, get_all_profiles
from ai import GolfAI, process_cpu_turn, get_all_profiles, reset_all_profiles
from game_log import get_logger
# Import production components
@ -193,6 +193,14 @@ async def lifespan(app: FastAPI):
# Close all WebSocket connections gracefully
await _close_all_websockets()
# Clean up all rooms and release CPU profiles
for room in list(room_manager.rooms.values()):
for cpu in list(room.get_cpu_players()):
room.remove_player(cpu.id)
room_manager.rooms.clear()
reset_all_profiles()
logger.info("All rooms and CPU profiles cleaned up")
# Cancel background tasks
if _leaderboard_refresh_task:
_leaderboard_refresh_task.cancel()
@ -392,6 +400,37 @@ async def require_admin(user: User = Depends(require_user)) -> User:
return user
# =============================================================================
# Debug Endpoints (CPU Profile Management)
# =============================================================================
@app.get("/api/debug/cpu-profiles")
async def get_cpu_profile_status():
"""Get current CPU profile allocation status."""
from ai import _used_profiles, _cpu_profiles, CPU_PROFILES
return {
"total_profiles": len(CPU_PROFILES),
"used_count": len(_used_profiles),
"used_profiles": list(_used_profiles),
"cpu_mappings": {cpu_id: profile.name for cpu_id, profile in _cpu_profiles.items()},
"active_rooms": len(room_manager.rooms),
"rooms": {
code: {
"players": len(room.players),
"cpu_players": [p.name for p in room.get_cpu_players()],
}
for code, room in room_manager.rooms.items()
},
}
@app.post("/api/debug/reset-cpu-profiles")
async def reset_cpu_profiles():
"""Reset all CPU profiles (emergency cleanup)."""
reset_all_profiles()
return {"status": "ok", "message": "All CPU profiles reset"}
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()