Skip to content

Commit

Permalink
Use cached_property to create Futures
Browse files Browse the repository at this point in the history
and avoid trying to access possibly non-existent event loop in init methods,
which allows to construct affected classes without a running event loop

fix flaky test
  • Loading branch information
Gatsik committed Jan 22, 2025
1 parent 181bee8 commit 20afe0a
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 9 deletions.
6 changes: 5 additions & 1 deletion server/games/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import pathlib
import time
from collections import defaultdict
from functools import cached_property
from typing import Any, Awaitable, Callable, Iterable, Optional

from sqlalchemy import and_, bindparam
Expand Down Expand Up @@ -132,12 +133,15 @@ def __init__(
self.game_options.add_callback("Title", self.on_title_changed)

self.mods = {}
self._hosted_future = asyncio.Future()
self._finish_lock = asyncio.Lock()

self._logger.debug("%s created", self)
asyncio.get_event_loop().create_task(self.timeout_game(setup_timeout))

@cached_property
def _hosted_future(self) -> asyncio.Future:
return asyncio.get_event_loop().create_future()

async def timeout_game(self, timeout: int = 60):
await asyncio.sleep(timeout)
if self.state is GameState.INITIALIZING:
Expand Down
7 changes: 4 additions & 3 deletions server/games/ladder_game.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import asyncio
import logging
from functools import cached_property
from typing import Optional

from server.config import config
Expand Down Expand Up @@ -27,9 +28,9 @@ class LadderGame(Game):
init_mode = InitMode.AUTO_LOBBY
game_type = GameType.MATCHMAKER

def __init__(self, id, *args, **kwargs):
super().__init__(id, *args, **kwargs)
self._launch_future = asyncio.Future()
@cached_property
def _launch_future(self) -> asyncio.Future:
return asyncio.get_event_loop().create_future()

async def wait_hosted(self, timeout: float):
return await asyncio.wait_for(
Expand Down
6 changes: 5 additions & 1 deletion server/matchmaker/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import math
import statistics
import time
from functools import cached_property
from typing import Any, Callable, Optional

import trueskill
Expand Down Expand Up @@ -41,13 +42,16 @@ def __init__(
self.players = players
self.rating_type = rating_type
self.start_time = start_time or time.time()
self._match = asyncio.get_event_loop().create_future()
self._failed_matching_attempts = 0
self.on_matched = on_matched

# Precompute this
self.quality_against_self = self.quality_with(self)

@cached_property
def _match(self) -> asyncio.Future:
return asyncio.get_event_loop().create_future()

def adjusted_rating(self, player: Player) -> Rating:
"""
Returns an adjusted mean with a simple linear interpolation between current mean and a specified base mean
Expand Down
6 changes: 2 additions & 4 deletions tests/integration_tests/test_matchmaker.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,8 @@ async def test_game_launch_message_game_options(lobby_server, tmp_user):
}


@pytest.mark.flaky
@fast_forward(15)
async def test_game_matchmaking_start(lobby_server, database):
async def test_game_matchmaking_start(lobby_server, database, game_service):
host_id, host, guest_id, guest = await queue_players_for_matchmaking(lobby_server)

# The player that queued last will be the host
Expand Down Expand Up @@ -139,8 +138,7 @@ async def test_game_matchmaking_start(lobby_server, database):
})

# Wait for db to be updated
await read_until_launched(host, game_id)
await read_until_launched(guest, game_id)
await game_service[game_id].wait_launched(None)

async with database.acquire() as conn:
result = await conn.execute(select(
Expand Down

0 comments on commit 20afe0a

Please sign in to comment.