Heartbeat timeout expires directly after connection is opened
Steps to reproduce on aioamqp 0.8.2:
- Have AMQP server which sends connection.tune method frame with parameter heartbeat = 0 (meaning turn heartbeats off)
- Do not pass heartbeat > 0 to aioamqp.connect()
Result:
- AmqpProtocol.start_connection() waits for connection.tune() to arrive on line 171
- On receiving connection.tune, AmqpProtocol.tune() sets
self.server_heartbeat = decoder.read_short() - start_connection proceeds to set key heartbeat to the tune_ok dictionary on line 176, but because user didn't pass heartbeat != None, it gets set to what the server sent (= 0)
- Client confirms heartbeat 0 with tune_ok() and self.server_heartbeat gets set to the same value 0 on line 184
- Line 186 skips calling _heartbeat_timer_recv_reset if self.server_heartbeat == 0, still OK
- Server replies with an connection.open-ok frame, and data_received calls
self._heartbeat_timer_recv_reset()unconditionally on line 108 - which checks if
self.server_heartbeat is None(which is never true, it's 0) - and _heartbeat_timer_recv_timeout is set to be called in 0 * 2, ie. 0 seconds
- which then silently just closes the writer on line 318
- which leads to connection_lost being called with no exception
- which leads to general kaboom.
Here's a traceback. Because connection.open-ok is the last frame the broker sends on establishing the connection, my code got to calling AmqpProtocol.channel() before getting an exception:
Traceback (most recent call last):
File "reproduce.py", line 123, in run
channel = yield from connection.channel()
File "/usr/lib/python3/dist-packages/aioamqp/protocol.py", line 444, in channel
yield from channel.open()
File "/usr/lib/python3/dist-packages/aioamqp/channel.py", line 134, in open
yield from fut
File "/usr/lib/python3.4/asyncio/futures.py", line 388, in __iter__
yield self # This tells Task to wait for completion.
File "/usr/lib/python3.4/asyncio/tasks.py", line 286, in _wakeup
value = future.result()
File "/usr/lib/python3.4/asyncio/futures.py", line 277, in result
raise self._exception
aioamqp.exceptions.ChannelClosed: (None, None)
Haven't tested locally, but that sounds about right. And it sucks!
Thanks for reporting! A PR would be much appreciated or we'll try to fix it as time allows.
Cheers
Experiencing the same thing, any news on the bugfix ? Thanks.
Sorry, no news unfortunately. Been busy with other work. A PR would be most appreciated.
Thanks
Hi @RemiCardona @mwfrojdman, I've made a simple workaround to solve this problem, it was so simple it sounds suspicious ... We need this feature for our work so any suggestion is welcome. Saludos!