Skip to content

Commit a92dd03

Browse files
arnaudmorinauvipy
authored andcommitted
Send heartbeat frames more often
The AMQP protocol is saying that we should send "two" "heartbeat frames" during the "heartbeat timeout" (see [1] and rabbit implement this in [2]). The "two" value is the "rate" parameter in the current implementation. The current implementation was sending only one frame during the "heartbeat timeout", which is wrong. [1] https://www.amqp.org/specification/0-9-1/amqp-org-download [2] https://www.rabbitmq.com/heartbeats.html#heartbeats-interval Signed-off-by: Arnaud Morin <[email protected]>
1 parent ab1edf9 commit a92dd03

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

amqp/connection.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -724,13 +724,18 @@ def heartbeat_tick(self, rate=2):
724724
once per second.
725725
726726
Keyword Arguments:
727-
rate (int): Previously used, but ignored now.
727+
rate (int): Number of heartbeat frames to send during the heartbeat
728+
timeout
728729
"""
729730
AMQP_HEARTBEAT_LOGGER.debug('heartbeat_tick : for connection %s',
730731
self._connection_id)
731732
if not self.heartbeat:
732733
return
733734

735+
# If rate is wrong, let's use 2 as default
736+
if rate <= 0:
737+
rate = 2
738+
734739
# treat actual data exchange in either direction as a heartbeat
735740
sent_now = self.bytes_sent
736741
recv_now = self.bytes_recv
@@ -755,7 +760,7 @@ def heartbeat_tick(self, rate=2):
755760
self.prev_sent, self.prev_recv = sent_now, recv_now
756761

757762
# send a heartbeat if it's time to do so
758-
if now > self.last_heartbeat_sent + self.heartbeat:
763+
if now > self.last_heartbeat_sent + self.heartbeat / rate:
759764
AMQP_HEARTBEAT_LOGGER.debug(
760765
'heartbeat_tick: sending heartbeat for connection %s',
761766
self._connection_id)

t/unit/test_connection.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import re
22
import socket
33
import warnings
4-
from array import array
54
from unittest.mock import Mock, call, patch
65

76
import pytest
7+
import time
88

99
from amqp import Connection, spec
1010
from amqp.connection import SSLError
@@ -514,6 +514,38 @@ def test_heartbeat_tick(self):
514514
with pytest.raises(ConnectionError):
515515
self.conn.heartbeat_tick()
516516

517+
def _test_heartbeat_rate_tick(self, rate):
518+
# Doing 22 calls,
519+
# First one is setting the variables
520+
# All nexts may send heartbeats, depending on rate
521+
for i in range(1, 22):
522+
self.conn.heartbeat_tick(rate)
523+
time.sleep(0.1)
524+
525+
def test_heartbeat_check_rate_default(self):
526+
# Heartbeat set to 2 secs
527+
self.conn.heartbeat = 2
528+
# Default rate is 2 --> should send frames every sec
529+
self._test_heartbeat_rate_tick(2)
530+
# Verify that we wrote 2 frames
531+
assert self.conn.frame_writer.call_count == 2
532+
533+
def test_heartbeat_check_rate_four(self):
534+
# Heartbeat set to 2 secs
535+
self.conn.heartbeat = 2
536+
# Rate 4 --> should send frames every 0.5sec
537+
self._test_heartbeat_rate_tick(4)
538+
# Verify that we wrote 4 frames
539+
assert self.conn.frame_writer.call_count == 4
540+
541+
def test_heartbeat_check_rate_wrong(self):
542+
# Heartbeat set to 2 secs
543+
self.conn.heartbeat = 2
544+
# Default rate is 2 --> should send frames every sec
545+
self._test_heartbeat_rate_tick(-42)
546+
# Verify that we wrote 2 frames
547+
assert self.conn.frame_writer.call_count == 2
548+
517549
def test_server_capabilities(self):
518550
self.conn.server_properties['capabilities'] = {'foo': 1}
519551
assert self.conn.server_capabilities == {'foo': 1}

0 commit comments

Comments
 (0)