##// END OF EJS Templates
close websocket connections on ping/pong timeout...
MinRK -
Show More
@@ -109,6 +109,25 b' WS_PING_INTERVAL = 30000'
109
109
110 class AuthenticatedZMQStreamHandler(ZMQStreamHandler, IPythonHandler):
110 class AuthenticatedZMQStreamHandler(ZMQStreamHandler, IPythonHandler):
111 ping_callback = None
111 ping_callback = None
112 last_pong = 0
113
114 @property
115 def ping_interval(self):
116 """The interval for websocket keep-alive pings.
117
118 Set ws_ping_interval = 0 to disable pings.
119 """
120 return self.settings.get('ws_ping_interval', WS_PING_INTERVAL)
121
122 @property
123 def ping_timeout(self):
124 """If no ping is received in this many milliseconds,
125 close the websocket connection (VPNs, etc. can fail to cleanly close ws connections).
126 Default is max of 3 pings or 30 seconds.
127 """
128 return self.settings.get('ws_ping_timeout',
129 max(3 * self.ping_interval, WS_PING_INTERVAL)
130 )
112
131
113 def set_default_headers(self):
132 def set_default_headers(self):
114 """Undo the set_default_headers in IPythonHandler
133 """Undo the set_default_headers in IPythonHandler
@@ -129,16 +148,30 b' class AuthenticatedZMQStreamHandler(ZMQStreamHandler, IPythonHandler):'
129 self.session = Session(config=self.config)
148 self.session = Session(config=self.config)
130 self.save_on_message = self.on_message
149 self.save_on_message = self.on_message
131 self.on_message = self.on_first_message
150 self.on_message = self.on_first_message
132 self.ping_callback = ioloop.PeriodicCallback(self.send_ping, WS_PING_INTERVAL)
151
133 self.ping_callback.start()
152 # start the pinging
153 if self.ping_interval > 0:
154 self.last_pong = ioloop.IOLoop.instance().time()
155 self.ping_callback = ioloop.PeriodicCallback(self.send_ping, self.ping_interval)
156 self.ping_callback.start()
134
157
135 def send_ping(self):
158 def send_ping(self):
136 """send a ping to keep the websocket alive"""
159 """send a ping to keep the websocket alive"""
137 if self.stream.closed() and self.ping_callback is not None:
160 if self.stream.closed() and self.ping_callback is not None:
138 self.ping_callback.stop()
161 self.ping_callback.stop()
139 return
162 return
163
164 # check for timeout on pong
165 since_last_pong = 1e3 * (ioloop.IOLoop.instance().time() - self.last_pong)
166 if since_last_pong > self.ping_timeout:
167 self.log.warn("WebSocket ping timeout after %i ms.", since_last_pong)
168 self.close()
169 return
140
170
141 self.ping(b'')
171 self.ping(b'')
172
173 def on_pong(self, data):
174 self.last_pong = ioloop.IOLoop.instance().time()
142
175
143 def _inject_cookie_message(self, msg):
176 def _inject_cookie_message(self, msg):
144 """Inject the first message, which is the document cookie,
177 """Inject the first message, which is the document cookie,
General Comments 0
You need to be logged in to leave comments. Login now