Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Matchmaking finalizers #357

Merged
merged 8 commits into from
Aug 25, 2021
Merged

Improve Matchmaking finalizers #357

merged 8 commits into from
Aug 25, 2021

Conversation

borzunov
Copy link
Member

@borzunov borzunov commented Aug 21, 2021

This PR resolves the frequent warning below, as well as a number of other finalizer issues.

Task was destroyed but it is pending!
task: <Task pending name='Task-11' coro=<PotentialLeaders._declare_averager_periodically() done, defined at /home/jheuristic/Documents/exp/hivemind/hivemind/averaging/matchmaking.py:513> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7efcec662fd0>()]>>

Discussion:

  • The new code does not return from begin_search() until declare_averager(..., looking_for_group=False) is finished. While it is idiomatic for asyncio, this makes averaging a little longer. Is it a desired behavior? Or maybe we should just suppress the Task was destroyed but it is pending! warning instead? Or maybe add to an averager-wide pool of background tasks?

@borzunov borzunov added the refactor Resolving technical debt label Aug 21, 2021
@codecov
Copy link

codecov bot commented Aug 21, 2021

Codecov Report

Merging #357 (ad57f86) into master (0e90183) will decrease coverage by 0.02%.
The diff coverage is 96.87%.

@@            Coverage Diff             @@
##           master     #357      +/-   ##
==========================================
- Coverage   83.43%   83.41%   -0.03%     
==========================================
  Files          66       66              
  Lines        6109     6095      -14     
==========================================
- Hits         5097     5084      -13     
+ Misses       1012     1011       -1     
Impacted Files Coverage Δ
hivemind/averaging/matchmaking.py 83.75% <95.45%> (-0.34%) ⬇️
hivemind/dht/__init__.py 89.47% <100.00%> (+0.23%) ⬆️
hivemind/utils/asyncio.py 98.71% <100.00%> (+2.82%) ⬆️
hivemind/utils/mpfuture.py 94.03% <0.00%> (-1.38%) ⬇️

@@ -521,8 +512,6 @@ async def _declare_averager_periodically(self, key_manager: GroupKeyManager):
await asyncio.sleep(self.declared_expiration_time - get_dht_time())
if self.running.is_set() and len(self.leader_queue) == 0:
await key_manager.update_key_on_not_enough_peers()
except (concurrent.futures.CancelledError, asyncio.CancelledError):
pass # note: this is a compatibility layer for python3.7
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[non-blocking]
Q: are you certain that we no longer need to handle concurrent.futures.CancelledError here or is it an educated guess?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have edited this PR to only remove the except statements in _update_queue_periodically() and _declare_averager_periodically() methods.

These methods are only awaited in cancel_and_wait() that handles both cancel and normal errors by itself.

@borzunov borzunov changed the title Remove outdated checks in Matchmaking Improve Matchmaking finalizers Aug 24, 2021
@borzunov borzunov force-pushed the refactor-matchmaking branch 5 times, most recently from 2c93456 to f670f40 Compare August 24, 2021 22:45
@@ -477,37 +475,31 @@ def request_expiration_time(self) -> float:
else:
return min(get_dht_time() + self.averaging_expiration, self.search_end_time)

async def _update_queue_periodically(self, key_manager: GroupKeyManager):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code is identical besides removing the try-except block (rationale is explained in this comment).

@@ -127,10 +127,9 @@ async def look_for_group(self, *, data_for_gather: bytes, timeout: Optional[floa
raise

finally:
if not request_leaders_task.done():
request_leaders_task.cancel()
if not self.assembled_group.done():
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.cancel() just returns False when the awaitable is done.

declare_averager_task.cancel()
await cancel_and_wait(update_queue_task)
if declare:
await cancel_and_wait(declare_averager_task)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using cancel_and_wait() here resolves this frequent warning:

Task was destroyed but it is pending!
task: <Task pending name='Task-11' coro=<PotentialLeaders._declare_averager_periodically() done, defined at /home/jheuristic/Documents/exp/hivemind/hivemind/averaging/matchmaking.py:513> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7efcec662fd0>()]>>

@borzunov borzunov marked this pull request as draft August 25, 2021 00:31
@borzunov borzunov marked this pull request as ready for review August 25, 2021 00:32
@@ -261,18 +261,11 @@ def run_coroutine(
async def _run_coroutine(
self, coro: Callable[[DHT, DHTNode], Awaitable[ReturnType]], future: MPFuture[ReturnType]
):
main_task = asyncio.create_task(coro(self, self._node))
Copy link
Member Author

@borzunov borzunov Aug 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cancels here did not work since the new MPFuture implementation does not support asyncio awaits in a child process.

They produced the following exception that was accidentally suppressed in await_cancelled():

Traceback (most recent call last):
  File "/home/borzunov/hivemind/hivemind/utils/asyncio.py", line 83, in await_cancelled
    await awaitable
  File "/home/borzunov/hivemind/hivemind/utils/mpfuture.py", line 284, in __await__
    raise RuntimeError("Can't await: MPFuture was created with no event loop")
RuntimeError: Can't await: MPFuture was created with no event loop

This PR removes them since they are not used, as discussed with @justheuristic.

hivemind/dht/__init__.py Outdated Show resolved Hide resolved
@borzunov borzunov merged commit 7f296a4 into master Aug 25, 2021
@borzunov borzunov deleted the refactor-matchmaking branch August 25, 2021 13:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
refactor Resolving technical debt
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants