I modified the code a little, so I make sure it is done and has no 
exception:

def done(fut):
    print("Future is done")
for task in conn_tasks:
    task.add_done_callback(done)
done, pending = yield from asyncio.wait(conn_tasks, timeout=5)
assert not pending
for task in done:
    assert task.exception() is None
    assert task.result() is None

This executes cleanly, without throwing an exception and prints "Future is 
done" for each connection.

On Friday, March 28, 2014 12:07:41 AM UTC+1, Guido van Rossum wrote:
>
> Looks to me like you're never asking for the result of those Futures 
> you're passing to asyncio.wait(). It waits until the Futures are complete, 
> but it doesn't inspect whether they have errors. You need something like
>
> for task in done:
>     if task.exception(): ...log it...
>
>
> On Thu, Mar 27, 2014 at 3:19 PM, Florian Rüchel 
> <[email protected]<javascript:>
> > wrote:
>
>> I can post the code, I just thought it might be too much. However, I'll 
>> just post the relevant section. Contrary to multithreaded programming here 
>> most of the times the local section is enough (I love asyncio :))
>>
>> Anyways here is the main function:
>>
>> try:
>>     self.event_loop.run_forever()
>> except KeyboardInterrupt:
>>     exit_main_loop()
>> finally:
>>      print("Running shutdown cleanup")
>>     collector.cancel()
>>
>>     @asyncio.coroutine
>>     def shutdown():
>>         yield from self.connection_pool.close()
>>     self.event_loop.run_until_complete(shutdown())
>>     self.event_loop.close()
>>
>> And the close method:
>>
>> @asyncio.coroutine
>> def close(self):
>>     try:
>>         if self.returned_connections:
>>             msg = ("Not all connections were returned: %s"
>>                    % self.returned_connections)
>>             log.error(msg)
>>             raise ValueError(msg)
>>     finally:
>>         conn_tasks = [asyncio.Task(conn.disconnect())
>>                       for conn in self.all_connections]
>>         done, pending = yield from asyncio.wait(conn_tasks, timeout=5)
>>         assert not pending
>>
>> Relevant is the finally part: I wrap each connection in a task and wait 
>> for them together. Removing the timeout did not help (I didn't expect it 
>> would, no exception is raised).
>>
>> Per existing connection (up to 10) a message is produced:
>>
>> 2014-03-27 23:11:58,143 ERROR[asyncio] Coroutine 'disconnect' defined at 
>> /path/to/library/connection.py:109 was never yielded from
>>
>> I have made sure that the amount of logging messages matches exactly the 
>> number of connections created (by counting the logging messages inside 
>> connection's __init__ function). In a very simple case there was only one 
>> connection, so only one error entry and only one log entry for a created 
>> connection.
>>
>> Hope this additional information helps uncover the issue. Thanks for the 
>> response.
>>
>> On Thursday, March 27, 2014 10:23:10 AM UTC+1, Florian Rüchel wrote:
>>>
>>> Hi everyone,
>>>
>>> I currently have a problem I cannot figure out. My code is running 
>>> perfectly fine, but when using "PYTHONASYNCIODEBUG=1" it reports that a 
>>> function was never yielded from per instance of that class I have. The 
>>> problem is I cannot create an example that replicates the issue and the 
>>> application is fairly large so maybe someone can give a hint on where I 
>>> might go looking. The function in question is a method of a connection 
>>> class. The class manages a TCP connection that has to send an init and a 
>>> disconnect request. It is the disconnect method that is reported as never 
>>> yielded from. I have log entries that prove that this function was actually 
>>> run and I have tried wrapping it in asyncio.Task and asyncio.async and I 
>>> also had a wrapping coroutine that *was *called and an explicit "yield 
>>> from connection.disconnect()" statement.
>>>
>>> In all three cases the proper log entries were written and the server 
>>> got the disconnect request, so I know it was properly executed. Now I am 
>>> wondering if I have a bug in my application that is hidden somewhere 
>>> between the layers that is repsonsible for this message. Or is it possible 
>>> to trigger this error message even though the function was properly called?
>>>
>>> I'd also like to note that this is *the only* method where this 
>>> happens, all other methods on all other classes are never reported as 
>>> problematic.I have checked the method against others but I cannot find any 
>>> difference at all: They are called with yield from or as tasks, they all 
>>> use other coroutines (the connect and disconnect method actually both use 
>>> *yield 
>>> from self.talk(...)*) and they are all properly decorated.
>>>
>>> I'm sorry I cannot provide any code examples, but since I am unable to 
>>> replicate the issue in a small sample, I fear I need further guidance on 
>>> where to look for the issue.
>>>
>>> Many thanks in advance and Regards,
>>> Florian
>>>
>>
>
>
> -- 
> --Guido van Rossum (python.org/~guido) 
>

Reply via email to