Skip to content

Commit b26acb7

Browse files
committed
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 4850c97 commit b26acb7

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
@@ -723,13 +723,18 @@ def heartbeat_tick(self, rate=2):
723723
once per second.
724724
725725
Keyword Arguments:
726-
rate (int): Previously used, but ignored now.
726+
rate (int): Number of heartbeat frames to send during the heartbeat
727+
timeout
727728
"""
728729
AMQP_HEARTBEAT_LOGGER.debug('heartbeat_tick : for connection %s',
729730
self._connection_id)
730731
if not self.heartbeat:
731732
return
732733

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

756761
# send a heartbeat if it's time to do so
757-
if now > self.last_heartbeat_sent + self.heartbeat:
762+
if now > self.last_heartbeat_sent + self.heartbeat / rate:
758763
AMQP_HEARTBEAT_LOGGER.debug(
759764
'heartbeat_tick: sending heartbeat for connection %s',
760765
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)