Skip to content

Dump backup #3001

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 29, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 60 additions & 8 deletions lib/API/Startup.js
Original file line number Diff line number Diff line change
Expand Up @@ -358,10 +358,29 @@ module.exports = function(CLI) {
* @return
*/
function fin(err) {
// Back up dump file
try {
if (fs.existsSync(cst.DUMP_FILE_PATH)) {
if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
fs.unlinkSync(cst.DUMP_BACKUP_FILE_PATH);
}
fs.renameSync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH);
}
} catch (e) {
console.error(e.stack || e);
Common.printOut(cst.PREFIX_MSG_ERR + 'Failed to back up dump file in %s', cst.DUMP_BACKUP_FILE_PATH);
}

// Overwrite dump file, delete if broken and exit
try {
fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify(env_arr, '', 2));
} catch (e) {
console.error(e.stack || e);
try {
fs.unlinkSync(cst.DUMP_FILE_PATH);
} catch (e) {
console.error(e.stack || e);
}
Common.printOut(cst.PREFIX_MSG_ERR + 'Failed to save dump file in %s', cst.DUMP_FILE_PATH);
return that.exitCli(cst.ERROR_EXIT);
}
Expand Down Expand Up @@ -393,19 +412,52 @@ module.exports = function(CLI) {
var apps = {};
var that = this;

Common.printOut(cst.PREFIX_MSG + 'Restoring processes located in %s', cst.DUMP_FILE_PATH);
var processes;

function readDumpFile(dumpFilePath) {
Common.printOut(cst.PREFIX_MSG + 'Restoring processes located in %s', cst.DUMP_FILE_PATH);
try {
var apps = fs.readFileSync(dumpFilePath);
} catch (e) {
Common.printError(cst.PREFIX_MSG_ERR + 'Failed to read dump file in %s', dumpFilePath);
throw e;
}

return apps;
}

function parseDumpFile(dumpFilePath, apps) {
try {
var processes = Common.parseConfig(apps, 'none');
} catch (e) {
Common.printError(cst.PREFIX_MSG_ERR + 'Failed to parse dump file in %s', dumpFilePath);
try {
fs.unlinkSync(dumpFilePath);
} catch (e) {
console.error(e.stack || e);
}
throw e;
}

return processes;
}

// Read dump file, fall back to backup, delete if broken
try {
apps = fs.readFileSync(cst.DUMP_FILE_PATH);
apps = readDumpFile(cst.DUMP_FILE_PATH);
processes = parseDumpFile(cst.DUMP_FILE_PATH, apps);
} catch(e) {
Common.printError(cst.PREFIX_MSG_ERR + 'No processes saved; DUMP file doesn\'t exist');
// if (cb) return cb(Common.retErr(e));
// else return that.exitCli(cst.ERROR_EXIT);
return that.speedList();
try {
apps = readDumpFile(cst.DUMP_BACKUP_FILE_PATH);
processes = parseDumpFile(cst.DUMP_BACKUP_FILE_PATH, apps);
} catch(e) {
Common.printError(cst.PREFIX_MSG_ERR + 'No processes saved; DUMP file doesn\'t exist');
// if (cb) return cb(Common.retErr(e));
// else return that.exitCli(cst.ERROR_EXIT);
return that.speedList();
}
}

var processes = Common.parseConfig(apps, 'none');

that.Client.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
Common.printError(err);
Expand Down
19 changes: 19 additions & 0 deletions lib/God/ActionMethods.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,30 @@ module.exports = function(God) {
}

function fin(err) {
// Back up dump file
try {
if (fs.existsSync(cst.DUMP_FILE_PATH)) {
if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
fs.unlinkSync(cst.DUMP_BACKUP_FILE_PATH);
}
fs.renameSync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH);
}
} catch (e) {
console.error(e.stack || e);
}

// Overwrite dump file, delete if broken
try {
fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify(process_list));
} catch (e) {
console.error(e.stack || e);
try {
fs.unlinkSync(cst.DUMP_FILE_PATH);
} catch (e) {
console.error(e.stack || e);
}
}

return cb(null, {success:true, process_list: process_list});
}

Expand Down
1 change: 1 addition & 0 deletions paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ module.exports = function(PM2_HOME) {
DEFAULT_MODULE_PATH : p.resolve(PM2_HOME, 'node_modules'),
KM_ACCESS_TOKEN : p.resolve(PM2_HOME, 'km-access-token'),
DUMP_FILE_PATH : p.resolve(PM2_HOME, 'dump.pm2'),
DUMP_BACKUP_FILE_PATH : p.resolve(PM2_HOME, 'dump.pm2.bak'),

DAEMON_RPC_PORT : p.resolve(PM2_HOME, 'rpc.sock'),
DAEMON_PUB_PORT : p.resolve(PM2_HOME, 'pub.sock'),
Expand Down
24 changes: 24 additions & 0 deletions test/bash/dump.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bash

SRC=$(cd $(dirname "$0"); pwd)
source "${SRC}/include.sh"
cd $file_path

$pm2 start echo.js -i 4
spec "should start 4 processes"
should 'should have 4 apps started' 'online' 4

rm -f ~/.pm2/dump.pm2 ~/.pm2/dump.pm2.bak
$pm2 save
spec "should save process list"
ls ~/.pm2/dump.pm2
spec "dump file should exist"
ls ~/.pm2/dump.pm2.bak
ispec "dump backup file should not exist"

$pm2 save
spec "should save and backup process list"
ls ~/.pm2/dump.pm2
spec "dump file should exist"
ls ~/.pm2/dump.pm2.bak
spec "dump backup file should exist"
18 changes: 14 additions & 4 deletions test/bash/resurrect.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,23 @@ cd $file_path

$pm2 start echo.js -i 4
spec "should start 4 processes"
should 'should have 4 apps started' 'online' 4

$pm2 save
spec "should save process list"
ls ~/.pm2/dump.pm2
spec "should dump file exists"
$pm2 resurrect
spec "should resurrect"
spec "should resurrect from dump"
should 'should have still 4 apps started' 'online' 4

$pm2 save
$pm2 delete all
echo "[{" > ~/.pm2/dump.pm2
$pm2 resurrect
spec "should resurrect from backup if dump is broken"
ls ~/.pm2/dump.pm2
ispec "should delete broken dump"
should 'should have still 4 apps started' 'online' 4

$pm2 delete all
$pm2 resurrect
spec "should resurrect from backup if dump is missing"
should 'should have still 4 apps started' 'online' 4
2 changes: 2 additions & 0 deletions test/pm2_behavior_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ bash ./test/bash/pm2-runtime.sh
spec "pm2-runtime"
bash ./test/bash/startup.sh
spec "upstart startup test"
bash ./test/bash/dump.sh
spec "dump test"
bash ./test/bash/resurrect.sh
spec "resurrect test"
# bash ./test/bash/docker.sh
Expand Down
91 changes: 88 additions & 3 deletions test/programmatic/misc_commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
var PM2 = require('../..');
var should = require('should');
var path = require('path');
var fs = require('fs');

var cst = require('../../constants.js');

describe('Misc commands', function() {
var pm2 = new PM2.custom({
Expand Down Expand Up @@ -31,7 +34,7 @@ describe('Misc commands', function() {
should(err).be.null();
done();
});
});
});

it('should restart them', function(done) {
pm2.restart('all', function(err, data) {
Expand Down Expand Up @@ -70,9 +73,34 @@ describe('Misc commands', function() {
});
});

it('should save process list', function(done) {
it('should save process list to dump', function(done) {
if (fs.existsSync(cst.DUMP_FILE_PATH)) {
fs.unlinkSync(cst.DUMP_FILE_PATH);
}

if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
fs.unlinkSync(cst.DUMP_BACKUP_FILE_PATH);
}

pm2.dump(function(err, data) {
should(fs.existsSync(cst.DUMP_FILE_PATH)).be.true();
should(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)).be.false();
should(err).be.null();
done();
});
});

it('should back up dump and re-save process list', function(done) {
var origDump = fs.readFileSync(cst.DUMP_FILE_PATH).toString();

pm2.dump(function(err, data) {
should(fs.existsSync(cst.DUMP_FILE_PATH)).be.true();
should(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)).be.true();
should(err).be.null();

var dumpBackup = fs.readFileSync(cst.DUMP_BACKUP_FILE_PATH).toString();

should(origDump).be.equal(dumpBackup);
done();
});
});
Expand All @@ -89,7 +117,7 @@ describe('Misc commands', function() {
});
});

it('should resurrect previous processes', function(done) {
it('should resurrect previous processes from dump', function(done) {
pm2.resurrect(function(err, data) {
should(err).be.null();

Expand All @@ -101,5 +129,62 @@ describe('Misc commands', function() {
});
});

it('should resurrect previous processes from backup if dump is broken', function(done) {
fs.writeFileSync(cst.DUMP_FILE_PATH, '[{');

pm2.resurrect(function(err, data) {
should(err).be.null();

pm2.list(function(err, procs) {
should(err).be.null();
procs.length.should.eql(4);
done();
});
});
});

it('should delete broken dump', function() {
should(fs.existsSync(cst.DUMP_FILE_PATH)).be.false();
});

it('should resurrect previous processes from backup if dump is missing', function(done) {
if (fs.existsSync(cst.DUMP_FILE_PATH)) {
fs.unlinkSync(cst.DUMP_FILE_PATH);
}

pm2.resurrect(function(err, data) {
should(err).be.null();

pm2.list(function(err, procs) {
should(err).be.null();
procs.length.should.eql(4);
done();
});
});
});

it('should resurrect no processes if dump and backup are broken', function() {
fs.writeFileSync(cst.DUMP_FILE_PATH, '[{');
fs.writeFileSync(cst.DUMP_BACKUP_FILE_PATH, '[{');

should(pm2.resurrect()).be.false();
});

it('should delete broken dump and backup', function() {
should(fs.existsSync(cst.DUMP_FILE_PATH)).be.false();
should(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)).be.false();
});

it('should resurrect no processes if dump and backup are missing', function() {
if (fs.existsSync(cst.DUMP_FILE_PATH)) {
fs.unlinkSync(cst.DUMP_FILE_PATH);
}

if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
fs.unlinkSync(cst.DUMP_BACKUP_FILE_PATH);
}

should(pm2.resurrect()).be.false();
});

});