aiozmq icon indicating copy to clipboard operation
aiozmq copied to clipboard

client not terminating on connection timeout

Open mentaal opened this issue 8 years ago • 4 comments

I have a question raised here on SO: http://stackoverflow.com/questions/38767067/python-program-not-exiting-on-exception-using-aiozmq which another user could reproduce.

Basically I am using rpc.connect_rpc with a timeout value. Once the timeout has exceeded, an exception is raised but the running program doesn't terminate. Details can be found from the aforementioned question.

mentaal avatar Aug 06 '16 09:08 mentaal

Here is a small example to reproduce this issue:

import asyncio
from aiozmq import rpc

async def client():
    client = await rpc.connect_rpc(
        connect='tcp://127.0.0.1:5555',
        timeout=1)
    return await client.call.some_function()

loop = asyncio.get_event_loop()
loop.run_until_complete(client())  

This program hangs after raising a TimeoutError, with two extra non-python threads running (zmq internal threads I would guess). Catching the TimeoutError and closing the loop doesn't help.

vxgmichel avatar Aug 06 '16 09:08 vxgmichel

@vxgmichel Out of curiosity, how did you determine that there are two extra non-python threads still running? As a more general question (or perhaps we should leave this for SO) how does this prevent the interpreter from dying?

mentaal avatar Aug 06 '16 10:08 mentaal

@mentaal I simply used htop:

 PID  PRI   NI  VIRT   RES   SHR S CPU% MEM%   TIME+  Command
 5608 20   0  250M 20532  9592 S  0.4  0.5  0:00.24 │  │  └─ python3.5 test_aiozmq.py
 5610 20   0  250M 20532  9592 S  0.4  0.5  0:00.13 │  │     ├─ python3.5 test_aiozmq.py
 5609 20   0  250M 20532  9592 S  0.0  0.5  0:00.00 │  │     └─ python3.5 test_aiozmq.py

You already showed in your SO question that no extra python threads are running after the exception is raised.

vxgmichel avatar Aug 06 '16 10:08 vxgmichel

I'm also stuck with this yesterday, after digging I found solution: http://api.zeromq.org/2-1%3azmq-setsockopt#toc15

For proper work, code should look like:

import asyncio

import aiozmq.rpc
import zmq


async def foo():

    client = await aiozmq.rpc.connect_rpc(connect="tcp://127.0.0.1:5555",
                                          timeout=1)
    client.transport.setsockopt(zmq.LINGER, 0)
    return await client.call.test()

loop = asyncio.get_event_loop()
loop.run_until_complete(foo())

Don't really know is it too bad, but I vote for setting LINGER to 0 at initialization period, since 99% don't care about it. The main problem of this solution is that pyzmq behavior will differ from aiozmq behavior.

pohmelie avatar Feb 17 '17 12:02 pohmelie