diff --git a/server/config.py b/server/config.py index 98082dfdc..7bffff5a7 100644 --- a/server/config.py +++ b/server/config.py @@ -148,6 +148,8 @@ def __init__(self): self.MAP_POOL_RATING_SELECTION = "mean" # The maximum amount of time in seconds to wait between pops self.QUEUE_POP_TIME_MAX = 90 + # The minimum amount of time in seconds to wait between pops + self.QUEUE_POP_TIME_MIN = 15 # The number of possible matches we would like to have when the queue # pops. The queue pop time will be adjusted based on the current rate of # players queuing to try and hit this number. diff --git a/server/matchmaker/pop_timer.py b/server/matchmaker/pop_timer.py index 5425707f9..e5894ca91 100644 --- a/server/matchmaker/pop_timer.py +++ b/server/matchmaker/pop_timer.py @@ -84,6 +84,14 @@ def time_until_next_pop(self, num_queued: int, time_queued: float) -> float: next_pop_time, self.queue.name, config.QUEUE_POP_TIME_MAX ) return config.QUEUE_POP_TIME_MAX + + if next_pop_time < config.QUEUE_POP_TIME_MIN: + self._logger.warning( + "Required time (%.2fs) for %s is lower than min pop time (%ds). ", + next_pop_time, self.queue.name, config.QUEUE_POP_TIME_MIN + ) + return config.QUEUE_POP_TIME_MIN + return next_pop_time def cancel(self): diff --git a/tests/unit_tests/test_matchmaker_queue.py b/tests/unit_tests/test_matchmaker_queue.py index db058bc11..134c31ce5 100644 --- a/tests/unit_tests/test_matchmaker_queue.py +++ b/tests/unit_tests/test_matchmaker_queue.py @@ -8,7 +8,7 @@ from hypothesis import strategies as st from server.config import config -from server.matchmaker import CombinedSearch, MapPool, PopTimer, Search +from server.matchmaker import CombinedSearch, MapPool, Search from server.players import PlayerState from server.rating import RatingType @@ -276,49 +276,6 @@ def test_combined_search_attributes(matchmaker_players): assert search.failed_matching_attempts == 2 -def test_queue_time_until_next_pop(queue_factory): - team_size = 2 - t1 = PopTimer(queue_factory(team_size=team_size)) - t2 = PopTimer(queue_factory(team_size=team_size)) - - desired_players = config.QUEUE_POP_DESIRED_MATCHES * team_size * 2 - - assert t1.time_until_next_pop(0, 0) == config.QUEUE_POP_TIME_MAX - # If the desired number of players is not reached within the maximum waiting - # time, then the next round must wait for the maximum allowed time as well. - a1 = t1.time_until_next_pop( - num_queued=desired_players - 1, - time_queued=config.QUEUE_POP_TIME_MAX - ) - assert a1 == config.QUEUE_POP_TIME_MAX - - # If there are more players than expected, the time should drop - a2 = t1.time_until_next_pop( - num_queued=desired_players * 2, - time_queued=config.QUEUE_POP_TIME_MAX - ) - assert a2 < a1 - - # Make sure that queue moving averages are calculated independently - assert t2.time_until_next_pop(0, 0) == config.QUEUE_POP_TIME_MAX - - -def test_queue_pop_time_moving_average_size(queue_factory): - t1 = PopTimer(queue_factory()) - - for _ in range(100): - t1.time_until_next_pop(100, 1) - - # The rate should be extremely high, meaning the pop time should be low - assert t1.time_until_next_pop(100, 1) < 1 - - for _ in range(config.QUEUE_POP_TIME_MOVING_AVG_SIZE): - t1.time_until_next_pop(0, 100) - - # The rate should be extremely low, meaning the pop time should be high - assert t1.time_until_next_pop(0, 100) == config.QUEUE_POP_TIME_MAX - - @given(rating=st.integers()) def test_queue_map_pools_empty(queue_factory, rating): queue = queue_factory() diff --git a/tests/unit_tests/test_pop_timer.py b/tests/unit_tests/test_pop_timer.py new file mode 100644 index 000000000..350a411db --- /dev/null +++ b/tests/unit_tests/test_pop_timer.py @@ -0,0 +1,45 @@ +from server.config import config +from server.matchmaker import PopTimer + + +def test_queue_time_until_next_pop(queue_factory): + team_size = 2 + t1 = PopTimer(queue_factory(team_size=team_size)) + t2 = PopTimer(queue_factory(team_size=team_size)) + + desired_players = config.QUEUE_POP_DESIRED_MATCHES * team_size * 2 + + assert t1.time_until_next_pop(0, 0) == config.QUEUE_POP_TIME_MAX + # If the desired number of players is not reached within the maximum waiting + # time, then the next round must wait for the maximum allowed time as well. + a1 = t1.time_until_next_pop( + num_queued=desired_players - 1, + time_queued=config.QUEUE_POP_TIME_MAX + ) + assert a1 == config.QUEUE_POP_TIME_MAX + + # If there are more players than expected, the time should drop + a2 = t1.time_until_next_pop( + num_queued=desired_players * 2, + time_queued=config.QUEUE_POP_TIME_MAX + ) + assert a2 < a1 + + # Make sure that queue moving averages are calculated independently + assert t2.time_until_next_pop(0, 0) == config.QUEUE_POP_TIME_MAX + + +def test_queue_pop_time_moving_average_size(queue_factory): + t1 = PopTimer(queue_factory()) + + for _ in range(100): + t1.time_until_next_pop(100, 1) + + # The rate should be extremely high, meaning the pop time should be low + assert t1.time_until_next_pop(100, 1) == config.QUEUE_POP_TIME_MIN + + for _ in range(config.QUEUE_POP_TIME_MOVING_AVG_SIZE): + t1.time_until_next_pop(0, 100) + + # The rate should be extremely low, meaning the pop time should be high + assert t1.time_until_next_pop(0, 100) == config.QUEUE_POP_TIME_MAX