Skip to content

Commit d66ad49

Browse files
authored
Merge pull request Unitech#3001 from bisubus/dump-backup
Dump backup
2 parents 874f1a7 + 548cc68 commit d66ad49

File tree

7 files changed

+208
-15
lines changed

7 files changed

+208
-15
lines changed

lib/API/Startup.js

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -358,10 +358,29 @@ module.exports = function(CLI) {
358358
* @return
359359
*/
360360
function fin(err) {
361+
// Back up dump file
362+
try {
363+
if (fs.existsSync(cst.DUMP_FILE_PATH)) {
364+
if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
365+
fs.unlinkSync(cst.DUMP_BACKUP_FILE_PATH);
366+
}
367+
fs.renameSync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH);
368+
}
369+
} catch (e) {
370+
console.error(e.stack || e);
371+
Common.printOut(cst.PREFIX_MSG_ERR + 'Failed to back up dump file in %s', cst.DUMP_BACKUP_FILE_PATH);
372+
}
373+
374+
// Overwrite dump file, delete if broken and exit
361375
try {
362376
fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify(env_arr, '', 2));
363377
} catch (e) {
364378
console.error(e.stack || e);
379+
try {
380+
fs.unlinkSync(cst.DUMP_FILE_PATH);
381+
} catch (e) {
382+
console.error(e.stack || e);
383+
}
365384
Common.printOut(cst.PREFIX_MSG_ERR + 'Failed to save dump file in %s', cst.DUMP_FILE_PATH);
366385
return that.exitCli(cst.ERROR_EXIT);
367386
}
@@ -393,19 +412,52 @@ module.exports = function(CLI) {
393412
var apps = {};
394413
var that = this;
395414

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

417+
function readDumpFile(dumpFilePath) {
418+
Common.printOut(cst.PREFIX_MSG + 'Restoring processes located in %s', cst.DUMP_FILE_PATH);
419+
try {
420+
var apps = fs.readFileSync(dumpFilePath);
421+
} catch (e) {
422+
Common.printError(cst.PREFIX_MSG_ERR + 'Failed to read dump file in %s', dumpFilePath);
423+
throw e;
424+
}
425+
426+
return apps;
427+
}
428+
429+
function parseDumpFile(dumpFilePath, apps) {
430+
try {
431+
var processes = Common.parseConfig(apps, 'none');
432+
} catch (e) {
433+
Common.printError(cst.PREFIX_MSG_ERR + 'Failed to parse dump file in %s', dumpFilePath);
434+
try {
435+
fs.unlinkSync(dumpFilePath);
436+
} catch (e) {
437+
console.error(e.stack || e);
438+
}
439+
throw e;
440+
}
441+
442+
return processes;
443+
}
444+
445+
// Read dump file, fall back to backup, delete if broken
398446
try {
399-
apps = fs.readFileSync(cst.DUMP_FILE_PATH);
447+
apps = readDumpFile(cst.DUMP_FILE_PATH);
448+
processes = parseDumpFile(cst.DUMP_FILE_PATH, apps);
400449
} catch(e) {
401-
Common.printError(cst.PREFIX_MSG_ERR + 'No processes saved; DUMP file doesn\'t exist');
402-
// if (cb) return cb(Common.retErr(e));
403-
// else return that.exitCli(cst.ERROR_EXIT);
404-
return that.speedList();
450+
try {
451+
apps = readDumpFile(cst.DUMP_BACKUP_FILE_PATH);
452+
processes = parseDumpFile(cst.DUMP_BACKUP_FILE_PATH, apps);
453+
} catch(e) {
454+
Common.printError(cst.PREFIX_MSG_ERR + 'No processes saved; DUMP file doesn\'t exist');
455+
// if (cb) return cb(Common.retErr(e));
456+
// else return that.exitCli(cst.ERROR_EXIT);
457+
return that.speedList();
458+
}
405459
}
406460

407-
var processes = Common.parseConfig(apps, 'none');
408-
409461
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
410462
if (err) {
411463
Common.printError(err);

lib/God/ActionMethods.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,30 @@ module.exports = function(God) {
137137
}
138138

139139
function fin(err) {
140+
// Back up dump file
141+
try {
142+
if (fs.existsSync(cst.DUMP_FILE_PATH)) {
143+
if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
144+
fs.unlinkSync(cst.DUMP_BACKUP_FILE_PATH);
145+
}
146+
fs.renameSync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH);
147+
}
148+
} catch (e) {
149+
console.error(e.stack || e);
150+
}
151+
152+
// Overwrite dump file, delete if broken
140153
try {
141154
fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify(process_list));
142155
} catch (e) {
143156
console.error(e.stack || e);
157+
try {
158+
fs.unlinkSync(cst.DUMP_FILE_PATH);
159+
} catch (e) {
160+
console.error(e.stack || e);
161+
}
144162
}
163+
145164
return cb(null, {success:true, process_list: process_list});
146165
}
147166

paths.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ module.exports = function(PM2_HOME) {
4848
DEFAULT_MODULE_PATH : p.resolve(PM2_HOME, 'node_modules'),
4949
KM_ACCESS_TOKEN : p.resolve(PM2_HOME, 'km-access-token'),
5050
DUMP_FILE_PATH : p.resolve(PM2_HOME, 'dump.pm2'),
51+
DUMP_BACKUP_FILE_PATH : p.resolve(PM2_HOME, 'dump.pm2.bak'),
5152

5253
DAEMON_RPC_PORT : p.resolve(PM2_HOME, 'rpc.sock'),
5354
DAEMON_PUB_PORT : p.resolve(PM2_HOME, 'pub.sock'),

test/bash/dump.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env bash
2+
3+
SRC=$(cd $(dirname "$0"); pwd)
4+
source "${SRC}/include.sh"
5+
cd $file_path
6+
7+
$pm2 start echo.js -i 4
8+
spec "should start 4 processes"
9+
should 'should have 4 apps started' 'online' 4
10+
11+
rm -f ~/.pm2/dump.pm2 ~/.pm2/dump.pm2.bak
12+
$pm2 save
13+
spec "should save process list"
14+
ls ~/.pm2/dump.pm2
15+
spec "dump file should exist"
16+
ls ~/.pm2/dump.pm2.bak
17+
ispec "dump backup file should not exist"
18+
19+
$pm2 save
20+
spec "should save and backup process list"
21+
ls ~/.pm2/dump.pm2
22+
spec "dump file should exist"
23+
ls ~/.pm2/dump.pm2.bak
24+
spec "dump backup file should exist"

test/bash/resurrect.sh

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,23 @@ cd $file_path
66

77
$pm2 start echo.js -i 4
88
spec "should start 4 processes"
9+
should 'should have 4 apps started' 'online' 4
10+
911
$pm2 save
10-
spec "should save process list"
11-
ls ~/.pm2/dump.pm2
12-
spec "should dump file exists"
1312
$pm2 resurrect
14-
spec "should resurrect"
13+
spec "should resurrect from dump"
1514
should 'should have still 4 apps started' 'online' 4
15+
16+
$pm2 save
17+
$pm2 delete all
18+
echo "[{" > ~/.pm2/dump.pm2
19+
$pm2 resurrect
20+
spec "should resurrect from backup if dump is broken"
21+
ls ~/.pm2/dump.pm2
22+
ispec "should delete broken dump"
23+
should 'should have still 4 apps started' 'online' 4
24+
1625
$pm2 delete all
1726
$pm2 resurrect
27+
spec "should resurrect from backup if dump is missing"
1828
should 'should have still 4 apps started' 'online' 4

test/pm2_behavior_tests.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ bash ./test/bash/pm2-runtime.sh
2525
spec "pm2-runtime"
2626
bash ./test/bash/startup.sh
2727
spec "upstart startup test"
28+
bash ./test/bash/dump.sh
29+
spec "dump test"
2830
bash ./test/bash/resurrect.sh
2931
spec "resurrect test"
3032
# bash ./test/bash/docker.sh

test/programmatic/misc_commands.js

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
var PM2 = require('../..');
44
var should = require('should');
55
var path = require('path');
6+
var fs = require('fs');
7+
8+
var cst = require('../../constants.js');
69

710
describe('Misc commands', function() {
811
var pm2 = new PM2.custom({
@@ -31,7 +34,7 @@ describe('Misc commands', function() {
3134
should(err).be.null();
3235
done();
3336
});
34-
});
37+
});
3538

3639
it('should restart them', function(done) {
3740
pm2.restart('all', function(err, data) {
@@ -70,9 +73,34 @@ describe('Misc commands', function() {
7073
});
7174
});
7275

73-
it('should save process list', function(done) {
76+
it('should save process list to dump', function(done) {
77+
if (fs.existsSync(cst.DUMP_FILE_PATH)) {
78+
fs.unlinkSync(cst.DUMP_FILE_PATH);
79+
}
80+
81+
if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
82+
fs.unlinkSync(cst.DUMP_BACKUP_FILE_PATH);
83+
}
84+
85+
pm2.dump(function(err, data) {
86+
should(fs.existsSync(cst.DUMP_FILE_PATH)).be.true();
87+
should(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)).be.false();
88+
should(err).be.null();
89+
done();
90+
});
91+
});
92+
93+
it('should back up dump and re-save process list', function(done) {
94+
var origDump = fs.readFileSync(cst.DUMP_FILE_PATH).toString();
95+
7496
pm2.dump(function(err, data) {
97+
should(fs.existsSync(cst.DUMP_FILE_PATH)).be.true();
98+
should(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)).be.true();
7599
should(err).be.null();
100+
101+
var dumpBackup = fs.readFileSync(cst.DUMP_BACKUP_FILE_PATH).toString();
102+
103+
should(origDump).be.equal(dumpBackup);
76104
done();
77105
});
78106
});
@@ -89,7 +117,7 @@ describe('Misc commands', function() {
89117
});
90118
});
91119

92-
it('should resurrect previous processes', function(done) {
120+
it('should resurrect previous processes from dump', function(done) {
93121
pm2.resurrect(function(err, data) {
94122
should(err).be.null();
95123

@@ -101,5 +129,62 @@ describe('Misc commands', function() {
101129
});
102130
});
103131

132+
it('should resurrect previous processes from backup if dump is broken', function(done) {
133+
fs.writeFileSync(cst.DUMP_FILE_PATH, '[{');
134+
135+
pm2.resurrect(function(err, data) {
136+
should(err).be.null();
137+
138+
pm2.list(function(err, procs) {
139+
should(err).be.null();
140+
procs.length.should.eql(4);
141+
done();
142+
});
143+
});
144+
});
145+
146+
it('should delete broken dump', function() {
147+
should(fs.existsSync(cst.DUMP_FILE_PATH)).be.false();
148+
});
149+
150+
it('should resurrect previous processes from backup if dump is missing', function(done) {
151+
if (fs.existsSync(cst.DUMP_FILE_PATH)) {
152+
fs.unlinkSync(cst.DUMP_FILE_PATH);
153+
}
154+
155+
pm2.resurrect(function(err, data) {
156+
should(err).be.null();
157+
158+
pm2.list(function(err, procs) {
159+
should(err).be.null();
160+
procs.length.should.eql(4);
161+
done();
162+
});
163+
});
164+
});
165+
166+
it('should resurrect no processes if dump and backup are broken', function() {
167+
fs.writeFileSync(cst.DUMP_FILE_PATH, '[{');
168+
fs.writeFileSync(cst.DUMP_BACKUP_FILE_PATH, '[{');
169+
170+
should(pm2.resurrect()).be.false();
171+
});
172+
173+
it('should delete broken dump and backup', function() {
174+
should(fs.existsSync(cst.DUMP_FILE_PATH)).be.false();
175+
should(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)).be.false();
176+
});
177+
178+
it('should resurrect no processes if dump and backup are missing', function() {
179+
if (fs.existsSync(cst.DUMP_FILE_PATH)) {
180+
fs.unlinkSync(cst.DUMP_FILE_PATH);
181+
}
182+
183+
if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
184+
fs.unlinkSync(cst.DUMP_BACKUP_FILE_PATH);
185+
}
186+
187+
should(pm2.resurrect()).be.false();
188+
});
104189

105190
});

0 commit comments

Comments
 (0)