Physikerwelt has uploaded a new change for review. https://gerrit.wikimedia.org/r/87699
Change subject: WIP: Ideas to make the node worker more robust ...................................................................... WIP: Ideas to make the node worker more robust Change-Id: If1d5ce7cf40932f9136f20fc3d06466cc67128d3 --- M mathoid/main.js M mathoid/mathoid-worker.js M mathoid/mathoid.js 3 files changed, 123 insertions(+), 35 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Math refs/changes/99/87699/1 diff --git a/mathoid/main.js b/mathoid/main.js index 312d4d9..7aac22a 100644 --- a/mathoid/main.js +++ b/mathoid/main.js @@ -41,11 +41,12 @@ data[0].length + 'B query, ERR ' + data[1][0] + t; out = JSON.stringify({err:data[1].message ,'log':log,'sucess':false}); resp.write(out); - console.log('error'+log); + //console.log('error'+log); }catch(err){ true; } //shutdown and wait for reboot + console.log('committing suicide on port '+PORT); phantom.exit(1); } resp.close(); @@ -72,7 +73,8 @@ window.engine.process(q, window.callPhantom); }, query); }catch(err){ - console.log('Unhandled error: ' + err.message); + //console.log('Unhandled error: ' + err.message); + console.log('committing suicide on port '+PORT); phantom.exit(1); } }); @@ -86,5 +88,5 @@ console.log(".. or by sending tex source in POST (not url encoded)"); }*/ }); - +console.log('READY on port '+PORT); diff --git a/mathoid/mathoid-worker.js b/mathoid/mathoid-worker.js index dfedb3b..3b729a7 100644 --- a/mathoid/mathoid-worker.js +++ b/mathoid/mathoid-worker.js @@ -14,6 +14,17 @@ var config; +var ready = false; +var starting = false; + +const STOPPED=0, + START_REQUEST=1, + STARTING=2, + START_SUCESS=3, + READY=4, + STOPREQUEST=5, + STOPPING=6; +var state = STOPPED; // Get the config try { config = JSON.parse(fs.readFileSync('./mathoid.config.json', 'utf8')); @@ -44,27 +55,76 @@ requestQueue = []; var startBackend = function () { - if (backend) { - backend.kill(); - } - var backendCB = function (err, stdout, stderr) { - if (err) { - restarts--; - if (restarts > 0) { - startBackend(); - } - console.error(err.toString()); - process.exit(1); + if ( state == START_REQUEST ){ + state = STARTING; + if (backend) { + backend.kill(); } - }; - backendPort = Math.floor(9000 + Math.random() * 50000); - console.error(instanceName + ': Starting backend on port ' + backendPort); - backend = child_process.exec('phantomjs main.js ' + backendPort, backendCB); - backend.stdout.pipe(process.stdout); - backend.stderr.pipe(process.stderr); + backend = null; + var stdoutListener; + var backendCB = function (err, stdout, stderr) { + if (err) { + restarts--; + if (restarts > 0) { + state = STOPREQUEST; + restartBackend(); + } + console.error('Strange-Error'+err.toString()); + console.log('Restarts:'+restarts); + //process.exit(1); + } + }; + var designatedBackendPort = Math.floor(9000 + Math.random() * 50000); + backend = child_process.exec('phantomjs main.js ' + designatedBackendPort, backendCB); + console.error( instanceName + ': Starting backend on port ' + designatedBackendPort); + backend.stdout.pipe(process.stdout); + backend.stderr.pipe(process.stderr); + backend.stdout.on('data', function (data) { + if (/^READY on port/.test(data)) { + var pattern = /\d+/ + var port = parseInt(data.match(pattern)); + if ( state == STARTING){ + state = START_SUCESS; + setTimeout(function(){ + backendPort= port; + console.log('phantom listing on port' + backendPort); + state = READY;} + ,500); + } else { + console.log('igore old startup:' + data); + } + }}); + backend.stdout.on('data', function (data) { + if (/committing/.test(data)) { + var pattern = /\d+/; + var port = parseInt(data.match(pattern)); + if (state == READY && port == backendPort ){ + state = STOPREQUEST; + console.log('phantom died at port '+port); + stopBackend(); + } else { + console.log('igore old shutdown: ' +data+ ' instead of '+ backendPort); + } + } + }); + } }; -startBackend(); +var stopBackend = function (){ + if (state == STOPREQUEST){ + state = STOPPING; + backend.kill(); + backendPort=0; + backend = null; + state = STOPPED; + } +}; +startBackend(); +var restartBackend = function(){ + stopBackend(); + state = START_REQUEST; + startBackend(); +}; /* -------------------- Web service --------------------- */ @@ -94,7 +154,7 @@ }; -function handleRequest(req, res, tex) { +function handleRequest(req, res, tex, oldPort) { // do the backend request var query = new Buffer(querystring.stringify({tex:tex})), options = { @@ -111,6 +171,7 @@ }; var chunks = []; //console.log(options); + var httpreq = http.request(options, function(httpres) { httpres.on('data', function(chunk) { chunks.push(chunk); @@ -127,31 +188,56 @@ requestQueue.shift(); handleRequests(); }); - }); - httpreq.on('error', function(err) { - console.log('error', err.toString()); - res.writeHead(500); - return res.end(JSON.stringify({error: "Backend error: " + err.toString()})); + httpres.on('error', function(err) { + if ( backendPort == oldPort ){ + if (state == READY){ + state = STOPREQUEST; + restartBackend(); + } + } + console.log(' http error', err.toString()); + res.writeHead(500); + return res.end(JSON.stringify({sucess:false,error: "Backend error: " + err.toString()})); + }); }); + httpreq.setTimeout(200); + httpreq.end(query); + } app.post(/^\/$/, function ( req, res ) { // First some rudimentary input validation if (!req.body.tex) { - res.writeHead(400); - return res.end(JSON.stringify({error: "'tex' post parameter is missing!"})); + res.writeHead(200); + return res.end(JSON.stringify({sucess:false,error: "'tex' post parameter is missing!"})); } var tex = req.body.tex; - - requestQueue.push(handleRequest.bind(null, req, res, tex)); - // phantomjs only handles one request at a time. Enforce this. - if (requestQueue.length === 1) { + console.log('getting'+tex); + console.log('readystate:'+state+' restarts: '+restarts ); + //if ( ! ready ){ setTimeout(function(){console.log('oha');},100) } + if ( state == READY ){ + console.log('ready'); + requestQueue.push(handleRequest.bind(null, req, res, tex, backendPort)); + // phantomjs only handles one request at a time. Enforce this. + if ( requestQueue.length === 1) { // Start this process handleRequests(); + } + } else if ( state === STOPPED ){ + state = START_REQUEST; + startBackend(); + return res.end(JSON.stringify({sucess:false, error: "Backend stopped...trying to restart"})); + } else if( state == STARTING) { + setTimeout(function(){ + if(state == STARTING){ + state = STOPPED; + }}, 2000); + return res.end(JSON.stringify({sucess:false, error: "Backend is starting"+state+"...try again later: "})); + } else { + return res.end(JSON.stringify({sucess:false, error: "Backend in state"+state+"...try again later: "})); } - }); diff --git a/mathoid/mathoid.js b/mathoid/mathoid.js index a1a4688..9d2a69d 100755 --- a/mathoid/mathoid.js +++ b/mathoid/mathoid.js @@ -12,7 +12,7 @@ // long-running request would otherwise hold up all concurrent short requests. var numCPUs = require('os').cpus().length + 3; // Fork workers. - for (var i = 0; i < numCPUs; i++) { + for (var i = 0; i < 1; i++) { cluster.fork(); } -- To view, visit https://gerrit.wikimedia.org/r/87699 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If1d5ce7cf40932f9136f20fc3d06466cc67128d3 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Math Gerrit-Branch: master Gerrit-Owner: Physikerwelt <w...@physikerwelt.de> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits