Merge pull request #1855 from minrk/rate-limit

iopub rate limit refinements
This commit is contained in:
Matthias Bussonnier 2016-11-02 11:24:37 -07:00 committed by GitHub
commit 64d996f820
2 changed files with 38 additions and 20 deletions

View File

@ -915,7 +915,7 @@ class NotebookApp(JupyterApp):
help="Reraise exceptions encountered loading server extensions?",
)
iopub_msg_rate_limit = Float(1000, config=True, help="""(msg/sec)
iopub_msg_rate_limit = Float(1000, config=True, help="""(msgs/sec)
Maximum rate at which messages can be sent on iopub before they are
limited.""")

View File

@ -8,6 +8,8 @@ Preliminary documentation at https://github.com/ipython/ipython/wiki/IPEP-16%3A-
import json
import logging
from textwrap import dedent
from tornado import gen, web
from tornado.concurrent import Future
from tornado.ioloop import IOLoop
@ -108,11 +110,11 @@ class ZMQChannelsHandler(AuthenticatedZMQStreamHandler):
@property
def iopub_msg_rate_limit(self):
return self.settings.get('iopub_msg_rate_limit', None)
return self.settings.get('iopub_msg_rate_limit', 0)
@property
def iopub_data_rate_limit(self):
return self.settings.get('iopub_data_rate_limit', None)
return self.settings.get('iopub_data_rate_limit', 0)
@property
def rate_limit_window(self):
@ -298,7 +300,7 @@ class ZMQChannelsHandler(AuthenticatedZMQStreamHandler):
def write_stderr(error_message):
self.log.warning(error_message)
msg = self.session.msg("stream",
content={"text": error_message, "name": "stderr"},
content={"text": error_message + '\n', "name": "stderr"},
parent=parent
)
msg['channel'] = 'iopub'
@ -306,6 +308,16 @@ class ZMQChannelsHandler(AuthenticatedZMQStreamHandler):
channel = getattr(stream, 'channel', None)
msg_type = msg['header']['msg_type']
if channel == 'iopub' and msg_type == 'status' and msg['content'].get('execution_state') == 'idle':
# reset rate limit counter on status=idle,
# to avoid 'Run All' hitting limits prematurely.
self._iopub_window_byte_queue = []
self._iopub_window_msg_count = 0
self._iopub_window_byte_count = 0
self._iopub_msgs_exceeded = False
self._iopub_data_exceeded = False
if channel == 'iopub' and msg_type not in {'status', 'comm_open', 'execute_input'}:
# Remove the counts queued for removal.
@ -320,7 +332,7 @@ class ZMQChannelsHandler(AuthenticatedZMQStreamHandler):
# This part of the queue hasn't be reached yet, so we can
# abort the loop.
break
# Increment the bytes and message count
self._iopub_window_msg_count += 1
byte_count = sum([len(x) for x in msg_list])
@ -336,39 +348,45 @@ class ZMQChannelsHandler(AuthenticatedZMQStreamHandler):
data_rate = float(self._iopub_window_byte_count) / self.rate_limit_window
# Check the msg rate
if self.iopub_msg_rate_limit is not None and msg_rate > self.iopub_msg_rate_limit and self.iopub_msg_rate_limit > 0:
if self.iopub_msg_rate_limit > 0 and msg_rate > self.iopub_msg_rate_limit:
if not self._iopub_msgs_exceeded:
self._iopub_msgs_exceeded = True
write_stderr("""iopub message rate exceeded. The
notebook server will temporarily stop sending iopub
messages to the client in order to avoid crashing it.
write_stderr(dedent("""\
IOPub message rate exceeded.
The notebook server will temporarily stop sending output
to the client in order to avoid crashing it.
To change this limit, set the config variable
`--NotebookApp.iopub_msg_rate_limit`.""")
return
`--NotebookApp.iopub_msg_rate_limit`."""))
else:
if self._iopub_msgs_exceeded:
# resume once we've got some headroom below the limit
if self._iopub_msgs_exceeded and msg_rate < (0.8 * self.iopub_msg_rate_limit):
self._iopub_msgs_exceeded = False
if not self._iopub_data_exceeded:
self.log.warning("iopub messages resumed")
# Check the data rate
if self.iopub_data_rate_limit is not None and data_rate > self.iopub_data_rate_limit and self.iopub_data_rate_limit > 0:
if self.iopub_data_rate_limit > 0 and data_rate > self.iopub_data_rate_limit:
if not self._iopub_data_exceeded:
self._iopub_data_exceeded = True
write_stderr("""iopub data rate exceeded. The
notebook server will temporarily stop sending iopub
messages to the client in order to avoid crashing it.
write_stderr(dedent("""\
IOPub data rate exceeded.
The notebook server will temporarily stop sending output
to the client in order to avoid crashing it.
To change this limit, set the config variable
`--NotebookApp.iopub_data_rate_limit`.""")
return
`--NotebookApp.iopub_data_rate_limit`."""))
else:
if self._iopub_data_exceeded:
# resume once we've got some headroom below the limit
if self._iopub_data_exceeded and data_rate < (0.8 * self.iopub_data_rate_limit):
self._iopub_data_exceeded = False
if not self._iopub_msgs_exceeded:
self.log.warning("iopub messages resumed")
# If either of the limit flags are set, do not send the message.
if self._iopub_msgs_exceeded or self._iopub_data_exceeded:
# we didn't send it, remove the current message from the calculus
self._iopub_window_msg_count -= 1
self._iopub_window_byte_count -= byte_count
self._iopub_window_byte_queue.pop(-1)
return
super(ZMQChannelsHandler, self)._on_zmq_reply(stream, msg)