[issue37658] In some cases asyncio.wait_for can lead to socket leak.

2019-07-23 Thread Nikita Ilyasov


Nikita Ilyasov  added the comment:

server example: https://gist.github.com/hexrain/bc92aa70eebc229365f0ce4bcccf7fc4

--

___
Python tracker 
<https://bugs.python.org/issue37658>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue37658] In some cases asyncio.wait_for can lead to socket leak.

2019-07-23 Thread Nikita Ilyasov

New submission from Nikita Ilyasov :

In some cases `asyncio.wait_for` can lead to socket leak.

Condensed example:

```python
async def _create_connection(timeout=60, ssl_obj):
loop = asyncio.get_event_loop()
connector = loop.create_connection(MyEchoClientProtocol, '127.0.0.1', 5000, 
ssl=ssl_obj)
connector = asyncio.ensure_future(connector)
tr, pr = await asyncio.wait_for(connector, timeout=timeout, loop=loop)
return tr, pr

async def main():
...
res = await asyncio.wait_for(_acquire_impl(), timeout=timeout, loop=loop)

```

If my understanding is correct `wait_for` should work in exactly 2 ways

1. the inner task is completed and the outer task will receive the result – 
transport and protocol in this case
2. The inner task is cancelled and no connection was established

I provided source code for client and server so the problem can be easily 
reproduced on your system.

certificate and key can be easily generated with `minica`


I found out that if I catch `CancelledError` and add a `done_callback` to the 
inner task, like so:

```python
try:
tr, pr = await asyncio.wait_for(connector, timeout=timeout, loop=loop)
return tr, pr
except asyncio.CancelledError as e:
connector.add_done_callback(_done_callback)
raise e
```
then inside of `_done_callback` I can access the transport and protocol object 
and close the transport manually to prevent leaking.


I run `netstat -a | grep 5000 | grep ESTAB | awk '{ print $5 }' | sort | uniq 
-c | grep 5000` after the script is done and there are many unclosed 
connections.

The output depends on your hardware so you might need to tweak the timeout 
parameter

--
components: asyncio
files: example.py
messages: 348328
nosy: Nikita Ilyasov, asvetlov, yselivanov
priority: normal
severity: normal
status: open
title: In some cases asyncio.wait_for can lead to socket leak.
type: resource usage
versions: Python 3.6, Python 3.7
Added file: https://bugs.python.org/file48500/example.py

___
Python tracker 
<https://bugs.python.org/issue37658>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com