Fix cancelled operation triggering asyncio uncaught exception handler #21
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The asyncio uncaught exception handler can be triggered when operations are cancelled, causing an error to be printed to stderr.
AsyncioContextBase._on_done() schedules a cross-thread call to Future.set_result, but doesn't check that the future is still not done before the call later runs on the asyncio thread. This allows for an operation to be cancelled in between the initial done() check and the set_result() call, which then fails, triggering the uncaught exception handler.
This PR fixes this by re-checking if the Future is done before calling set_result().
I can imagine you don't necessarily need a test for this, as it's a deterministic thing, but putting in a test was the easiest way to reproduce/demonstrate the issue. You can see it failing for the current version by checking out the test commit and running:
You should see the test fail, and the captured output to stderr will contain errors logged by the asyncio uncaught exception handler like this:
I'm getting these kind of errors logged by my app due to this (I'm doing something similar to the test here, reading a bunch of chunks from a file concurrently/eagerly, and at some point deciding to cancel the remaining read operations.