diff --git a/daphne/cli.py b/daphne/cli.py index ae301eb..57724ef 100755 --- a/daphne/cli.py +++ b/daphne/cli.py @@ -73,6 +73,12 @@ class CommandLineInterface(object): help='The number of seconds a WebSocket must be idle before a keepalive ping is sent', default=20, ) + self.parser.add_argument( + '--ping-timeout', + type=int, + help='The number of seconds before a WeSocket is closed if no response to a keepalive ping', + default=30, + ) self.parser.add_argument( 'channel_layer', help='The ASGI channel layer instance to use as path.to.module:instance.path', @@ -143,6 +149,7 @@ class CommandLineInterface(object): file_descriptor=args.file_descriptor, http_timeout=args.http_timeout, ping_interval=args.ping_interval, + ping_timeout=args.ping_timeout, action_logger=AccessLogGenerator(access_log_stream) if access_log_stream else None, ws_protocols=args.ws_protocols, root_path=args.root_path, diff --git a/daphne/http_protocol.py b/daphne/http_protocol.py index 4171886..f3e7d62 100755 --- a/daphne/http_protocol.py +++ b/daphne/http_protocol.py @@ -276,7 +276,7 @@ class HTTPFactory(http.HTTPFactory): protocol = HTTPProtocol - def __init__(self, channel_layer, action_logger=None, timeout=120, websocket_timeout=86400, ping_interval=20, ws_protocols=None, root_path=""): + def __init__(self, channel_layer, action_logger=None, timeout=120, websocket_timeout=86400, ping_interval=20, ping_timeout=30, ws_protocols=None, root_path=""): http.HTTPFactory.__init__(self) self.channel_layer = channel_layer self.action_logger = action_logger @@ -287,6 +287,7 @@ class HTTPFactory(http.HTTPFactory): self.reply_protocols = {} # Make a factory for WebSocket protocols self.ws_factory = WebSocketFactory(self, protocols=ws_protocols) + self.ws_factory.setProtocolOptions(autoPingTimeout=ping_timeout) self.ws_factory.protocol = WebSocketProtocol self.ws_factory.reply_protocols = self.reply_protocols self.root_path = root_path diff --git a/daphne/server.py b/daphne/server.py index bd6335d..e13276e 100755 --- a/daphne/server.py +++ b/daphne/server.py @@ -23,6 +23,7 @@ class Server(object): http_timeout=120, websocket_timeout=None, ping_interval=20, + ping_timeout=30, ws_protocols=None, root_path="", ): @@ -35,6 +36,7 @@ class Server(object): self.action_logger = action_logger self.http_timeout = http_timeout self.ping_interval = ping_interval + self.ping_timeout = ping_timeout # If they did not provide a websocket timeout, default it to the # channel layer's group_expiry value if present, or one day if not. self.websocket_timeout = websocket_timeout or getattr(channel_layer, "group_expiry", 86400) @@ -48,6 +50,7 @@ class Server(object): timeout=self.http_timeout, websocket_timeout=self.websocket_timeout, ping_interval=self.ping_interval, + ping_timeout=self.ping_timeout, ws_protocols=self.ws_protocols, root_path=self.root_path, ) diff --git a/daphne/ws_protocol.py b/daphne/ws_protocol.py index e42af82..dfa8adc 100755 --- a/daphne/ws_protocol.py +++ b/daphne/ws_protocol.py @@ -189,7 +189,7 @@ class WebSocketProtocol(WebSocketServerProtocol): Checks to see if we should send a keepalive ping. """ if (time.time() - self.last_data) > self.main_factory.ping_interval: - self.sendPing() + self._sendAutoPing() self.last_data = time.time()