New submission from Johannes Ebke:

In a very specific case, asyncio.gather causes a cancel() call on the Task 
waiting on the _GatheringFuture to return a false positive. An example program 
demonstrating this is attached.

The context: asyncio.gather creates a _GatheringFuture with a list of child 
Futures. Each child Future carries a done callback that updates the 
_GatheringFuture, and once the last child done callback is executed, the 
_GatheringFuture sets its result.

The specific situation: When the last child future changes state to done it 
schedules its done callbacks, but does not immediately execute them. If the 
Task waiting on the gather is then cancelled before the last child done 
callback has run, the cancel method in asyncio/tasks.py:578 determines that the 
_GatheringFuture inspects itself and sees that it is not done() yet, and 
proceeds to cancel all child futures - which has no effect, since all of them 
are already done(). It still returns True, so the Tasks thinks all is well, and 
proceeds with its execution.

The behaviour I would expect is that if cancel() is called on the 
_GatheringFuture, and all children return False on cancel(), then 
_GatheringFuture.cancel() should also return False, i.e.:

def cancel(self):
    if self.done():
        return False
    at_least_one_child_cancelled = False
    for child in self._children:
        if child.cancel():
            at_least_one_child_cancelled = True
    return at_least_one_child_cancelled

If I replace _GatheringFuture.cancel with the above variant, the bug disappears 
for me.

More context: We hit this bug sporadically in an integration test of aioredis, 
where some timings conspired to make it appear with a chance of about 1 in 10. 
The minimal example calls the cancellation in a done_callback, so that it 
always hits the window. This was not the way the bug was discovered.

----------
components: asyncio
files: cancellation_test.py
messages: 264719
nosy: JohannesEbke, gvanrossum, haypo, yselivanov
priority: normal
severity: normal
status: open
title: asyncio.gather drops cancellation
type: behavior
versions: Python 3.5
Added file: http://bugs.python.org/file42694/cancellation_test.py

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue26923>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to