Skip to content

Commit

Permalink
Configurable ping interval grace period (Fixes #134)
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelgrinberg committed Aug 9, 2019
1 parent 441a323 commit bb24013
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 9 deletions.
6 changes: 5 additions & 1 deletion engineio/asyncio_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ class AsyncServer(server.Server):
:param ping_timeout: The time in seconds that the client waits for the
server to respond before disconnecting.
:param ping_interval: The interval in seconds at which the client pings
the server.
the server. The default is 25 seconds. For advanced
control, a two element tuple can be given, where
the first number is the ping interval and the second
is a grace period added by the server. The default
grace period is 5 seconds.
:param max_http_buffer_size: The maximum size of a message when using the
polling transport.
:param allow_upgrades: Whether to allow transport upgrades or not.
Expand Down
3 changes: 2 additions & 1 deletion engineio/asyncio_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ async def check_ping_timeout(self):
"""
if self.closed:
raise exceptions.SocketIsClosedError()
if time.time() - self.last_ping > self.server.ping_interval + 5:
if time.time() - self.last_ping > self.server.ping_interval + \
self.server.ping_interval_grace_period:
self.server.logger.info('%s: Client is gone, closing socket',
self.sid)
# Passing abort=False here will cause close() to write a
Expand Down
13 changes: 11 additions & 2 deletions engineio/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ class Server(object):
server to respond before disconnecting. The default
is 60 seconds.
:param ping_interval: The interval in seconds at which the client pings
the server. The default is 25 seconds.
the server. The default is 25 seconds. For advanced
control, a two element tuple can be given, where
the first number is the ping interval and the second
is a grace period added by the server. The default
grace period is 5 seconds.
:param max_http_buffer_size: The maximum size of a message when using the
polling transport. The default is 100,000,000
bytes.
Expand Down Expand Up @@ -83,7 +87,12 @@ def __init__(self, async_mode=None, ping_timeout=60, ping_interval=25,
cors_credentials=True, logger=False, json=None,
async_handlers=True, monitor_clients=None, **kwargs):
self.ping_timeout = ping_timeout
self.ping_interval = ping_interval
if isinstance(ping_interval, tuple):
self.ping_interval = ping_interval[0]
self.ping_interval_grace_period = ping_interval[1]
else:
self.ping_interval = ping_interval
self.ping_interval_grace_period = 5
self.max_http_buffer_size = max_http_buffer_size
self.allow_upgrades = allow_upgrades
self.http_compression = http_compression
Expand Down
3 changes: 2 additions & 1 deletion engineio/socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ def check_ping_timeout(self):
"""
if self.closed:
raise exceptions.SocketIsClosedError()
if time.time() - self.last_ping > self.server.ping_interval + 5:
if time.time() - self.last_ping > self.server.ping_interval + \
self.server.ping_interval_grace_period:
self.server.logger.info('%s: Client is gone, closing socket',
self.sid)
# Passing abort=False here will cause close() to write a
Expand Down
6 changes: 4 additions & 2 deletions tests/asyncio/test_asyncio_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def _get_mock_server(self):
mock_server = mock.Mock()
mock_server.ping_timeout = 0.2
mock_server.ping_interval = 0.2
mock_server.ping_interval_grace_period = 0.001
mock_server.async_handlers = False
mock_server._async = {'asyncio': True,
'create_route': mock.MagicMock(),
Expand Down Expand Up @@ -124,9 +125,10 @@ def test_invalid_packet(self):

def test_timeout(self):
mock_server = self._get_mock_server()
mock_server.ping_interval = -6
mock_server.ping_interval = 6
mock_server.ping_interval_grace_period = 2
s = asyncio_socket.AsyncSocket(mock_server, 'sid')
s.last_ping = time.time() - 1
s.last_ping = time.time() - 9
s.close = AsyncMock()
_run(s.send('packet'))
s.close.mock.assert_called_once_with(wait=False, abort=False)
Expand Down
6 changes: 6 additions & 0 deletions tests/common/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ def test_create(self):
s = server.Server(**kwargs)
for arg in six.iterkeys(kwargs):
self.assertEqual(getattr(s, arg), kwargs[arg])
self.assertEqual(s.ping_interval_grace_period, 5)

def test_create_with_grace_period(self):
s = server.Server(ping_interval=(1, 2))
self.assertEqual(s.ping_interval, 1)
self.assertEqual(s.ping_interval_grace_period, 2)

def test_create_ignores_kwargs(self):
server.Server(foo='bar') # this should not raise
Expand Down
6 changes: 4 additions & 2 deletions tests/common/test_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def _get_mock_server(self):
mock_server = mock.Mock()
mock_server.ping_timeout = 0.2
mock_server.ping_interval = 0.2
mock_server.ping_interval_grace_period = 0.001
mock_server.async_handlers = True

try:
Expand Down Expand Up @@ -109,9 +110,10 @@ def test_invalid_packet(self):

def test_timeout(self):
mock_server = self._get_mock_server()
mock_server.ping_interval = -6
mock_server.ping_interval = 6
mock_server.ping_interval_grace_period = 2
s = socket.Socket(mock_server, 'sid')
s.last_ping = time.time() - 1
s.last_ping = time.time() - 9
s.close = mock.MagicMock()
s.send('packet')
s.close.assert_called_once_with(wait=False, abort=False)
Expand Down

0 comments on commit bb24013

Please sign in to comment.