You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
2.6 KiB
110 lines
2.6 KiB
5 years ago
|
/* Dumps the redis DB to rdb, then uploads that to S3.
|
||
|
* Configure below, and provide upkeep/credentials.json.
|
||
|
*/
|
||
|
|
||
|
var AWS = require('aws-sdk'),
|
||
|
config = require('../config'),
|
||
|
crypto = require('crypto'),
|
||
|
db = require('../db'),
|
||
|
fs = require('fs');
|
||
|
|
||
|
var BUCKET = 'backupbucket';
|
||
|
var ACL = 'bucket-owner-full-control';
|
||
|
var RDB_PATH = '/Users/lalc/dump.rdb';
|
||
|
var BGSAVE_TIMEOUT = 5*60;
|
||
|
|
||
|
var r, s3;
|
||
|
|
||
|
function dump_rdb(cb) {
|
||
|
console.log('Dumping rdb...');
|
||
|
r.lastsave(function (err, lastSave) {
|
||
|
if (err) return err;
|
||
|
r.bgsave(function (err) {
|
||
|
if (err) return err;
|
||
|
setTimeout(poll_for_lastsave_after.bind(null,
|
||
|
lastSave, 0, cb), 200);
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function poll_for_lastsave_after(lastSave, seconds, cb) {
|
||
|
// Will take slightly longer than BGSAVE_TIMEOUT seconds since
|
||
|
// we're waiting for a lastsave command between each second
|
||
|
if (seconds > BGSAVE_TIMEOUT)
|
||
|
return cb("bgsave timeout");
|
||
|
|
||
|
r.lastsave(function (err, newSave) {
|
||
|
if (err)
|
||
|
return cb(err);
|
||
|
if (newSave > lastSave) {
|
||
|
console.log('Obtained dump after', seconds, 'sec');
|
||
|
check_mtime(RDB_PATH, newSave, cb);
|
||
|
return;
|
||
|
}
|
||
|
if (newSave < lastSave)
|
||
|
return cb("Time travel");
|
||
|
setTimeout(poll_for_lastsave_after.bind(null,
|
||
|
lastSave, seconds+1, cb), 1000);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function check_mtime(path, lastsave, cb) {
|
||
|
console.log(' redis lastsave:', lastsave);
|
||
|
fs.stat(path, function (err, stat) {
|
||
|
if (err)
|
||
|
return cb(err);
|
||
|
var mtime = Math.floor(stat.mtime.getTime() / 1000);
|
||
|
console.log(' ' + path + ' mtime:', mtime);
|
||
|
if (Math.abs(mtime - lastsave) > 1000)
|
||
|
return cb("Bad mtime: "+lastsave+" != "+mtime);
|
||
|
cb(null);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function upload(kind, filename, cb) {
|
||
|
var now = new Date();
|
||
|
var random = crypto.randomBytes(8).toString('hex');
|
||
|
var dir = now.getUTCFullYear() + '-' + pad2(now.getUTCMonth()+1);
|
||
|
var name = dir+'-'+pad2(now.getUTCDate()) + '-' + kind + '-' + random;
|
||
|
var key = dir + '/' + name;
|
||
|
|
||
|
var stream = fs.createReadStream(filename);
|
||
|
var params = {
|
||
|
ACL: ACL,
|
||
|
Bucket: BUCKET,
|
||
|
Key: key,
|
||
|
Body: stream,
|
||
|
};
|
||
|
|
||
|
process.stdout.write('Writing s3://'+BUCKET+'/'+key+' ...');
|
||
|
s3.putObject(params, function (err, data) {
|
||
|
if (err) {
|
||
|
console.log('failed!');
|
||
|
return cb(err);
|
||
|
}
|
||
|
console.log('done.');
|
||
|
console.log('ETag:', data.ETag);
|
||
|
cb(null);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function pad2(n) {
|
||
|
return (n < 10 ? '0' : '') + n;
|
||
|
}
|
||
|
|
||
|
if (require.main == module) {
|
||
|
s3 = new AWS.S3().client;
|
||
|
s3.config.loadFromPath('upkeep/credentials.json');
|
||
|
r = db.redis_client();
|
||
|
|
||
|
dump_rdb(function (err) {
|
||
|
if (err)
|
||
|
throw err;
|
||
|
upload('dump.rdb', RDB_PATH, function (err) {
|
||
|
if (err)
|
||
|
throw err;
|
||
|
process.exit(0);
|
||
|
});
|
||
|
});
|
||
|
}
|