Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Heartbeat timeout expires directly after connection is opened #119

Open
mwfrojdman opened this issue Nov 14, 2016 · 4 comments
Open

Heartbeat timeout expires directly after connection is opened #119

mwfrojdman opened this issue Nov 14, 2016 · 4 comments
Labels

Comments

@mwfrojdman
Copy link
Contributor

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)
@RemiCardona
Copy link
Contributor

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

@nemiliani
Copy link

Experiencing the same thing, any news on the bugfix ? Thanks.

@RemiCardona
Copy link
Contributor

Sorry, no news unfortunately. Been busy with other work. A PR would be most appreciated.

Thanks

@clodo
Copy link

clodo commented May 25, 2017

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants