Skip to content
This repository has been archived by the owner on Sep 3, 2022. It is now read-only.

Commit

Permalink
Remove a check that could cause Datalab to hang.
Browse files Browse the repository at this point in the history
The previous version of the code checked that a launched Jupyter
process reported that it was listening on the port we asked it to
listen on.

However, the launched process may have written that message before
we started reading its output, and this would cause us to hang forever
waiting for the Jupyter server to report a one-time message that we
had already missed.
  • Loading branch information
ojarjur committed Jun 30, 2016
1 parent e462f08 commit 73167c5
Showing 1 changed file with 23 additions and 32 deletions.
55 changes: 23 additions & 32 deletions sources/web/datalab/jupyter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,15 @@ var templates: common.Map<string> = {
*/
var appSettings: common.Settings;

function pipeOutput(server: JupyterServer, stream: NodeJS.ReadableStream, port: number, error: boolean) {
function pipeOutput(stream: NodeJS.ReadableStream, port: number, error: boolean) {
stream.setEncoding('utf8');
var listeningMessage = `The IPython Notebook is running at:`;

stream.on('data', (data: string) => {
// Jupyter generates a polling kernel message once every 3 seconds
// per kernel! This adds too much noise into the log, so avoid
// logging it.

if (data.indexOf('Polling kernel') < 0) {
if (data.indexOf(listeningMessage) >= 0) {
server.portResolved();
}
logging.logJupyterOutput('[' + port + ']: ' + data, error);
}
})
Expand Down Expand Up @@ -127,34 +123,29 @@ function createJupyterServer(userId: string, remainingAttempts: number) {
logging.getLogger().info('Jupyter process for user %s started with pid %d and args %j',
userId, server.childProcess.pid, processArgs);

server.portResolved = function() {
// Ensure that the portResolved function only gets invoked once.
server.portResolved = function(){};

// Create the proxy.
var proxyOptions: httpProxy.ProxyServerOptions = {
target: 'http://127.0.0.1:' + port
};

server.proxy = httpProxy.createProxyServer(proxyOptions);
server.proxy.on('proxyRes', responseHandler);
server.proxy.on('error', errorHandler);

tcp.waitUntilUsed(server.port, 100, 3000).then(
function() {
jupyterServers[userId] = server;
logging.getLogger().info('Jupyter server started for %s.', userId);
callbackManager.invokeAllCallbacks(userId, null);
},
function(e) {
logging.getLogger().error(e, 'Failed to start Jupyter server for user %s.', userId);
callbackManager.invokeAllCallbacks(userId, e);
});
}

// Capture the output, so it can be piped for logging.
pipeOutput(server, server.childProcess.stdout, server.port, /* error */ false);
pipeOutput(server, server.childProcess.stderr, server.port, /* error */ true);
pipeOutput(server.childProcess.stdout, server.port, /* error */ false);
pipeOutput(server.childProcess.stderr, server.port, /* error */ true);

// Create the proxy.
var proxyOptions: httpProxy.ProxyServerOptions = {
target: 'http://127.0.0.1:' + port
};

server.proxy = httpProxy.createProxyServer(proxyOptions);
server.proxy.on('proxyRes', responseHandler);
server.proxy.on('error', errorHandler);

tcp.waitUntilUsed(server.port, 100, 3000).then(
function() {
jupyterServers[userId] = server;
logging.getLogger().info('Jupyter server started for %s.', userId);
callbackManager.invokeAllCallbacks(userId, null);
},
function(e) {
logging.getLogger().error(e, 'Failed to start Jupyter server for user %s.', userId);
callbackManager.invokeAllCallbacks(userId, e);
});
},
function(e) {
logging.getLogger().error(e, 'Failed to find a free port at %d', port);
Expand Down

0 comments on commit 73167c5

Please sign in to comment.