Use cached_property to create Futures#1038
Conversation
Askaholic
left a comment
There was a problem hiding this comment.
Sorry it took me a while to review. I wasn't sure about the approach at first, but after thinking about it for a while, I think I like it! I have just one question about the implementation, and one comment about the test change.
server/games/game.py
Outdated
|
|
||
| @cached_property | ||
| def _hosted_future(self) -> asyncio.Future: | ||
| return asyncio.get_event_loop().create_future() |
There was a problem hiding this comment.
Should we be using get_running_loop instead maybe? I'm not entirely sure what all the intricacies are but the asyncio docs for get_event_loop in python 3.10 say this:
Because this function has rather complex behavior (especially when custom event loop policies are in use), using the get_running_loop() function is preferred to get_event_loop() in coroutines and callbacks.
| # 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) |
There was a problem hiding this comment.
I feel like this change wouldn't make any difference. In fact, as far as I can tell from the code the read_until_launched method should actually always wait longer than the wait_launched method. So I'm not sure if this actually fixes the flakiness or if maybe you just got lucky when running the tests. But I could be missing something.
I also want to keep these integration tests using only the protocol messages as much as possible. So if we can use a protocol message to determine that the game launched instead of having to reach into the internal state of a service, that would be much better. That way it can reveal deficiencies in our protocol if there are some use cases that are not possible using only the existing messages.
There was a problem hiding this comment.
Hey! Yes, you are missing a few things here:
- Setting player options marks game as dirty
read_until_launchedmethod haslaunched_atas a criteria of game launch, which it receives from server message- Sending
launched_atis not event-based -- broadcast service reports dirties every (more or less) fixed interval (currently it is 1 second) launched_atis set before updates to the database are made (they happen inon_game_launchedmethod):
Lines 727 to 739 in 9d6ba68
awaitstatements tell event loop that it can process some other scheduled tasks
fast_forward just exaggerates timing discrepancies -- report_dirties does not wait full second between reports -- therefore reporting happens during database update more often.
But the test can fail even without fast_forward -- just tweak the sleep time here (0.01 and 0.99 worked for me):
server/tests/integration_tests/test_matchmaker.py
Lines 126 to 133 in 9d6ba68
(I also don't completely understand the purpose of this sleep, I suppose it 'simulates' launching fa process on the client side). Anyway, some change to broadcast interval can break this test
On the other hand, wait_launched method of ladder_game is event-based -- it always sets its _launch_future after database update (which happens in super class):
server/server/games/ladder_game.py
Lines 46 to 48 in 9d6ba68
If you wanted to find deficiencies in protocol -- it is the one.
There's also another thing: at least in integration_tests services are initialized twice -- first time in their corresponding fixtures, and the second time here:
server/tests/integration_tests/conftest.py
Line 161 in 9d6ba68
because
instance.started is False
I split this PR in 2 commits, so if you insist on leaving flaky test as is you can drop the fix
20afe0a to
63abe7a
Compare
and avoid trying to access possibly non-existent event loop in init methods, which allows to construct affected classes without a running event loop
63abe7a to
08fd6e6
Compare
Resolves #894
Also, fix one flaky test (
test_game_matchmaking_start) by fully waiting for the game to start.I took a look at other flaky tests, but I couldn't reproduce their flakiness: they had been continuing to pass.
The only flaky one which sometimes failed is
test_game_matchmaking_close_fa_and_requeue, and I believe this is happening due to@fast_forwardnot working as wished withloop.run_in_executorfutures.Removing
@fast_forwarddecorator fixes this test's flakiness, but increases runtime (from ~1 to about ~2.5 seconds), so I didn't touch that.