mirror of
https://github.com/jupyter/notebook.git
synced 2025-01-06 11:35:24 +08:00
Handle kernel messages synchronously
A problem can happen when two messages come in for different comms, where the second depends on the first (for example, the first might be a message setting the state of a widget, and the second triggering a view creation for the widget). Since comm message queues are independent of each other, the second message could be executed before the first message. This exposes a more fundamental assumption users are likely to have that messages from python are processed synchronously. Thanks to @dmadeka for reporting an error that led to discovering this issue.
This commit is contained in:
parent
2eb028bcec
commit
e1a6dbd4be
@ -117,6 +117,7 @@ define([
|
||||
// don't return a comm, so that further .then() functions
|
||||
// get an undefined comm input
|
||||
});
|
||||
return this.comms[content.comm_id];
|
||||
};
|
||||
|
||||
CommManager.prototype.comm_msg = function(msg) {
|
||||
@ -134,6 +135,7 @@ define([
|
||||
}
|
||||
return comm;
|
||||
});
|
||||
return this.comms[content.comm_id];
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
@ -855,22 +855,23 @@ define([
|
||||
};
|
||||
|
||||
Kernel.prototype._handle_ws_message = function (e) {
|
||||
var that = this;
|
||||
this._msg_queue = this._msg_queue.then(function() {
|
||||
return serialize.deserialize(e.data);
|
||||
}).then($.proxy(this._finish_ws_message, this))
|
||||
}).then(function(msg) {return that._finish_ws_message(msg);})
|
||||
.catch(utils.reject("Couldn't process kernel message", true));
|
||||
};
|
||||
|
||||
Kernel.prototype._finish_ws_message = function (msg) {
|
||||
switch (msg.channel) {
|
||||
case 'shell':
|
||||
this._handle_shell_reply(msg);
|
||||
return this._handle_shell_reply(msg);
|
||||
break;
|
||||
case 'iopub':
|
||||
this._handle_iopub_message(msg);
|
||||
return this._handle_iopub_message(msg);
|
||||
break;
|
||||
case 'stdin':
|
||||
this._handle_input_request(msg);
|
||||
return this._handle_input_request(msg);
|
||||
break;
|
||||
default:
|
||||
console.error("unrecognized message channel", msg.channel, msg);
|
||||
@ -879,10 +880,12 @@ define([
|
||||
|
||||
Kernel.prototype._handle_shell_reply = function (reply) {
|
||||
this.events.trigger('shell_reply.Kernel', {kernel: this, reply:reply});
|
||||
var that = this;
|
||||
var content = reply.content;
|
||||
var metadata = reply.metadata;
|
||||
var parent_id = reply.parent_header.msg_id;
|
||||
var callbacks = this.get_callbacks_for_msg(parent_id);
|
||||
var promise = Promise.resolve();
|
||||
if (!callbacks || !callbacks.shell) {
|
||||
return;
|
||||
}
|
||||
@ -892,17 +895,21 @@ define([
|
||||
this._finish_shell(parent_id);
|
||||
|
||||
if (shell_callbacks.reply !== undefined) {
|
||||
shell_callbacks.reply(reply);
|
||||
promise = promise.then(function() {return shell_callbacks.reply(reply)});
|
||||
}
|
||||
if (content.payload && shell_callbacks.payload) {
|
||||
this._handle_payloads(content.payload, shell_callbacks.payload, reply);
|
||||
promise = promise.then(function() {
|
||||
return that._handle_payloads(content.payload, shell_callbacks.payload, reply);
|
||||
});
|
||||
}
|
||||
return promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function _handle_payloads
|
||||
*/
|
||||
Kernel.prototype._handle_payloads = function (payloads, payload_callbacks, msg) {
|
||||
var promise = [];
|
||||
var l = payloads.length;
|
||||
// Payloads are handled by triggering events because we don't want the Kernel
|
||||
// to depend on the Notebook or Pager classes.
|
||||
@ -910,9 +917,10 @@ define([
|
||||
var payload = payloads[i];
|
||||
var callback = payload_callbacks[payload.source];
|
||||
if (callback) {
|
||||
callback(payload, msg);
|
||||
promise.push(callback(payload, msg));
|
||||
}
|
||||
}
|
||||
return Promise.all(promise);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1025,7 +1033,7 @@ define([
|
||||
Kernel.prototype._handle_iopub_message = function (msg) {
|
||||
var handler = this.get_iopub_handler(msg.header.msg_type);
|
||||
if (handler !== undefined) {
|
||||
handler(msg);
|
||||
return handler(msg);
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user