Hum, I didn't get any reply to this message :-( I opened an issue to
at least document the behaviour:
https://bugs.python.org/issue23859

By the way, while discussing with Natim on IRC, we found a bug in the
websockets project which uses wait() on a queue.get() task. If the
wait() is cancelled, you can loose an item of the queue if the get
task is not called. See my fix:

diff --git a/websockets/protocol.py b/websockets/protocol.py
index 7e4a94e..5353b74 100644
--- a/websockets/protocol.py
+++ b/websockets/protocol.py
@@ -166,9 +166,13 @@ class
WebSocketCommonProtocol(asyncio.StreamReaderProtocol):

         # Wait for a message until the connection is closed
         next_message = asyncio.async(self.messages.get(), loop=self._loop)
-        done, pending = yield from asyncio.wait(
-                [next_message, self.worker],
-                loop=self._loop, return_when=asyncio.FIRST_COMPLETED)
+        try:
+            done, pending = yield from asyncio.wait(
+                    [next_message, self.worker],
+                    loop=self._loop, return_when=asyncio.FIRST_COMPLETED)
+        except:
+            next_message.cancel()
+            raise
         if next_message in done:
             return next_message.result()
         else:

The full recv() method:
https://github.com/aaugustin/websockets/blob/7d8191699a6d647c1b45e3e11681c5987437e5b5/websockets/protocol.py#L149

Victor

2015-01-29 10:06 GMT+01:00 Victor Stinner <[email protected]>:
> Hi,
>
> While I tried to write a example cancelling create_connection(), I saw
> that asynico.wait() doesn't cancel waited tasks when it is cancelled.
>
> In the following example, the result of fut is never used, so asyncio
> emits a warning (exception never retrieved):
> ---
> import asyncio
>
> def func():
>     fut = asyncio.Future()
>     fs = [fut]
>     fut2 = loop.create_task(asyncio.wait(fs))
>     fut2.cancel()
>     fut.set_exception(ValueError("never catched"))
>     try:
>         yield from fut2
>     except asyncio.CancelledError:
>         pass
>     # nobody cares of fut result?
>
> loop = asyncio.get_event_loop()
> loop.run_until_complete(func())
> loop.close()
> ---
>
> Is it correct that wait() doesn't cancel waited tasks?
>
> wait_for() was modified recently to cancel the waited task when
> wait_for() is cancelled:
> http://bugs.python.org/issue23219
>
> asyncio.gather() does cancel tasks when it is cancelled:
> https://docs.python.org/dev/library/asyncio-task.html#asyncio.gather
>
> If wait() must not cancel tasks, it should be better explained in the
> documentation and asyncio code should be audited to ensure that tasks
> are explicitly cancelled.
>
> For example, replace:
>
>     yield from tasks.wait(fs, loop=self)
>
> with:
>
>     try:
>         yield from tasks.wait(fs, loop=self)
>     except CancelledError:
>         for fut in fs:
>             fut.cancel()
>
> I only found one method calling wait(): create_connection().
>
> Victor

Reply via email to