Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set timeout for tornado IOStream?

How to set timeout for tornado IOStream?

I've tried construct IOStream by:

sock = socket.socket()
sock.settimeout(5)
self.stream = tornado.iostream.IOStream(sock)

But when I call stream.read_bytes(), it still keep waiting forever.

like image 595
3xian Avatar asked Aug 07 '13 03:08

3xian


1 Answers

You cannot use socket.settimeout(), because it is designed for blocking IO and Tornado provides non-blocking IO.

Tornado is highly oriented on Web and HTTP IO and it does not allow to do low-level network programming without extreme pain (sources of IOStream are terrifying).

The best way to set a timeout on a socket is to use select.select(), select.poll(), etc, but it's a pain to integrate such approach with Tornado.

I've managed to perform reads with timeouts using combination of gen.with_timeout and a dirty hack for clearing stream's state.

from tornado import gen
from tornado.ioloop import IOLoop
from tornado.tcpclient import TCPClient

timeout = 5
io_loop = IOLoop.current()
factory = TCPClient(io_loop=io_loop)

@gen.coroutine
def run():
    stream = yield factory.connect('127.0.0.1', 1234)
    try:
        future = stream.read_bytes(128)
        data = yield gen.with_timeout(
            timeout=io_loop.time() + timeout,
            future=future,
            io_loop=io_loop,
        )
    except gen.TimeoutError:
        # A dirty hack to cancel reading and to clear state of the stream, so
        # stream will be available for reading in future
        io_loop.remove_handler(stream.socket)
        state = (stream._state & ~io_loop.READ)
        stream._state = None
        stream._read_callback = None
        stream._read_future = None
        stream._add_io_state(state)

Good luck!

like image 142
oblalex Avatar answered Sep 27 '22 23:09

oblalex