Let NodeJS App Update With NPM

Hej there

I am trying to add some non-standard features to a NodeJS application, but I am having problems. I am trying to do the following:

I want to update the server code from the client. (Auto-update feature if you do.)

My first attempt was to use the NPM API and run:

npm.commands.install([package], function(err, data) 

But of course, this leads to an error indicating that NPM cannot install while the server is running.

My second attempt is updating NPM with the following code:

  spawnProcess('npm', ['update'], { cwd: projectPath }, done); 

The spawnProcess function is a generic appearance function:

 var projectPath = path.resolve(process.cwd()); var spawnProcess = function(command, args, options, callback) { var spawn = require('child_process').spawn; var process = spawn(command, args, options); var err = false; process.stdout.on('data', function(data) { console.log('stdout', data.toString()); }); process.stderr.on('data', function(data) { err = true; console.log('stderr', data.toString()); }); if (typeof callback === 'function') { process.on('exit', function() { if (!err) { return callback(); } }); } }; 

But that gives me stderr, followed by the CreateProcessW error: can not find file. I do not quite understand what I am doing wrong.

If all else fails, I thought it would be possible to write killscript kill Node, updating the application and reloading it. Sort of:

 kill -9 45728 npm update node server 

But I do not know if this is a plausible solution and how I will execute it from my node server. I would prefer the caviar function to work, of course.

Any help is appreciated. Thanks in advance!

+6
source share
3 answers

So, I finally fixed this problem. If anyone is interested in how I did this, here's how:

I built a function using the NPM api to check if the current version is updated:

  exports.checkVersion = function(req, res) { npm.load([], function (err, npm) { npm.commands.search(["mediacenterjs"], function(err, data){ if (err){ console.log('NPM search error ' + err); return; } else{ var currentInfo = checkCurrentVersion(); for (var key in data) { var obj = data[key]; if(obj.name === 'mediacenterjs' && obj.version > currentInfo.version){ var message = 'New version '+obj.version+' Available'; res.json(message); } } } }); }); } var checkCurrentVersion = function(){ var info = {}; var data = fs.readFileSync('./package.json' , 'utf8'); try{ info = JSON.parse(data); }catch(e){ console.log('JSON Parse Error', e); } return info; }; 

If the version is not updated, I start the download (in my case the github master repository URL) using node-wget:

 var wget = require('wget'); var download = wget.download(src, output, options); download.on('error', function(err) { console.log('Error', err); callback(output); }); download.on('end', function(output) { console.log(output); callback(output); }); download.on('progress', function(progress) { console.log(progress * 100); }); 

The callback drops the unzip database on the @John Munsch Self Help script, but I added a check to check if there was a previous unpack attempt, and if so, I delete the folder:

 if(fs.existsSync(dir) === false){ fs.mkdirSync(dir); } else { rimraf(dir, function (err) { if(err) { console.log('Error removing temp folder', err); } else { fileHandler.downloadFile(src, output, options, function(output){ console.log('Done', output); unzip(req, res, output, dir); }); } }); } console.log("Unzipping New Version..."); var AdmZip = require("adm-zip"); var zip = new AdmZip(output); zip.extractAllTo(dir, true); fs.openSync('./configuration/update.js', 'w'); 

The openSync function runs my NodeMon-based file ( https://github.com/jansmolders86/mediacenterjs/blob/master/server.js ), which kills the server as it lists the changes for that particular file. Finally, it reboots and launches the following functions:

 function installUpdate(output, dir){ console.log('Installing update...'); var fsExtra = require("fs.extra"); fsExtra.copy(dir+'/mediacenterjs-master', './', function (err) { if (err) { console.error('Error', err); } else { console.log("success!"); cleanUp(output, dir); } }); } function cleanUp(output, dir) { console.log('Cleanup...'); var rimraf = require('rimraf'); rimraf(dir, function (e) { if(e) { console.log('Error removing module', e .red); } }); if(fs.existsSync(output) === true){ fs.unlinkSync(output); console.log('Done, restarting server...') server.start(); } } 

Thanks to everyone who helped me!

+6
source

Not verified!

Have you tried handling the "prestart" npm script handle ? Of course, this would mean that you would use npm to start your server: npm start

In your .json package (if any):

 { "scripts" : { "start" : "node server.js", "prestart" : "scripts/customScript.js" } } 

The NPM start command is implicitly defaulted to "start": "node server.js". If your server script is called server.js, there is no need to include it. You can either install npm on customScript.js or perhaps you can directly call npm install, although I have not tested this.

You can also assign / read a handler using the environment variable process.env.npm_package_scripts_prestart

+3
source

It does not use NPM to execute it, but here is a working experiment that I put together a while ago because I wanted to create a self-updating application using Node.js to install on people's computers (think of applications like SABnzbd +, Couch Potato or Plex Media Server).

Github for sample code is here: https://github.com/JohnMunsch/selfhelp

I got an example until it automatically tells you when a new version will be available, and then download, update and restart. Even if you do not use it as is, you can get some ideas from it.

+1
source

All Articles