aio-libs/aiozmq

Application never stops when backend is not running.

ithinuel opened this issue · 2 comments

This very simple test shows that the script never stops when then backend is not running.

#!/usr/bin/env python3

import threading
import logging
import asyncio
from aiozmq import rpc

logging.getLogger().setLevel(logging.DEBUG)

async def go():
    logging.debug('Go !')
    client = None
    try:
        client = await rpc.connect_rpc(connect='tcp://127.0.0.1:5555', timeout=5)
        await client.call.remote(1, 2)
    except Exception as e:
        logging.exception(e)
    finally:
        if client is not None:
            client.close()
            await client.wait_closed()

    logging.debug('done')

loop = asyncio.get_event_loop()
loop.run_until_complete(go())
loop.close()

logging.debug(asyncio.Task.all_tasks())
logging.debug(threading.enumerate())

You will notice that both coros (go & the one we wait_for) are done and python only tracks the MainThread.
But you can see in top (htop/strace) that the script has actually 2 threads running.

  • 1 blocked on an epoll_wait(10,
  • 1 looping on :
epoll_wait(13, [], 256, 168)            = 0
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
fcntl(3, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
connect(3, {sa_family=AF_INET, sin_port=htons(5555), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
epoll_ctl(13, EPOLL_CTL_ADD, 3, {0, {u32=1275071824, u64=140476770422096}}) = 0
epoll_ctl(13, EPOLL_CTL_MOD, 3, {EPOLLOUT, {u32=1275071824, u64=140476770422096}}) = 0
epoll_wait(13, [{EPOLLOUT|EPOLLERR|EPOLLHUP, {u32=1275071824, u64=140476770422096}}], 256, -1) = 1
epoll_ctl(13, EPOLL_CTL_DEL, 3, 0x7fc34c000d54) = 0
getsockopt(3, SOL_SOCKET, SO_ERROR, [111], [4]) = 0
close(3)                                = 0

I am not 100% sure, but I think the EPOLLOUT|EPOLLERR|EPOLLHUP that we receive is the HUP=HangUp=ConnectionRefused.

I tracked down the remaining/invisible threads to be somewhere in the zmq library.

This issue is a copy of this stackoverflow question.

Can You try to take a look on #72 (comment)

client.transport.setsockopt(zmq.LINGER, 0)

might help You

Hi, indeed it helped (a lot) !

I will tag my question as a duplicate of the previous one and add quote this as an accepted answer.

Thank you.