Crash on reindex
- Introduced the concept of a Cancellation error so that services can choose to watch for a cancellation flag. - Services can then send this error back and it will be forwarded to the node. - The node will then know to call shutdown appropriately.
This commit is contained in:
parent
dc6d0e681c
commit
4ee11ed73b
@ -15,11 +15,14 @@ Consensus.BlockExists = createError('BlockExists', Consensus);
|
|||||||
var Transaction = createError('Transaction', BitcoreNodeError);
|
var Transaction = createError('Transaction', BitcoreNodeError);
|
||||||
Transaction.NotFound = createError('NotFound', Transaction);
|
Transaction.NotFound = createError('NotFound', Transaction);
|
||||||
|
|
||||||
|
var Cancellation = createError('Cancellation', BitcoreNodeError);
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
Error: BitcoreNodeError,
|
Error: BitcoreNodeError,
|
||||||
NoOutputs: NoOutputs,
|
NoOutputs: NoOutputs,
|
||||||
NoOutput: NoOutput,
|
NoOutput: NoOutput,
|
||||||
Wallet: Wallet,
|
Wallet: Wallet,
|
||||||
Consensus: Consensus,
|
Consensus: Consensus,
|
||||||
Transaction: Transaction
|
Transaction: Transaction,
|
||||||
|
Cancellation: Cancellation
|
||||||
};
|
};
|
||||||
|
|||||||
23
lib/node.js
23
lib/node.js
@ -22,7 +22,7 @@ function Node(config) {
|
|||||||
this.network = null;
|
this.network = null;
|
||||||
this.services = {};
|
this.services = {};
|
||||||
this._unloadedServices = [];
|
this._unloadedServices = [];
|
||||||
this._loadingServices = {};
|
this.started = false;
|
||||||
|
|
||||||
// TODO type check the arguments of config.services
|
// TODO type check the arguments of config.services
|
||||||
if (config.services) {
|
if (config.services) {
|
||||||
@ -141,16 +141,15 @@ Node.prototype._startService = function(serviceInfo, callback) {
|
|||||||
config.node = this;
|
config.node = this;
|
||||||
config.name = serviceInfo.name;
|
config.name = serviceInfo.name;
|
||||||
var service = new serviceInfo.module(config);
|
var service = new serviceInfo.module(config);
|
||||||
self._loadingServices[service.name] = service;
|
|
||||||
|
// include in loaded services
|
||||||
|
self.services[serviceInfo.name] = service;
|
||||||
|
|
||||||
service.start(function(err) {
|
service.start(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
// include in loaded services
|
|
||||||
self.services[serviceInfo.name] = service;
|
|
||||||
|
|
||||||
// add API methods
|
// add API methods
|
||||||
var methodData = service.getAPIMethods();
|
var methodData = service.getAPIMethods();
|
||||||
var methodNameConflicts = [];
|
var methodNameConflicts = [];
|
||||||
@ -188,16 +187,24 @@ Node.prototype.start = function(callback) {
|
|||||||
self._startService(service, next);
|
self._startService(service, next);
|
||||||
},
|
},
|
||||||
function(err) {
|
function(err) {
|
||||||
if (err) {
|
if (err instanceof errors.Cancellation) {
|
||||||
|
self.cancellation = true;
|
||||||
|
return callback(err);
|
||||||
|
} else if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
self.emit('ready');
|
self.emit('ready');
|
||||||
|
self.started = true;
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
Node.prototype.stop = function(callback) {
|
Node.prototype.stop = function(callback) {
|
||||||
|
if (!this.started && !this.cancellation) {
|
||||||
|
this.pendingStop = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
log.info('Beginning shutdown');
|
log.info('Beginning shutdown');
|
||||||
var self = this;
|
var self = this;
|
||||||
var services = this.getServiceOrder().reverse();
|
var services = this.getServiceOrder().reverse();
|
||||||
@ -208,9 +215,9 @@ Node.prototype.stop = function(callback) {
|
|||||||
async.eachSeries(
|
async.eachSeries(
|
||||||
services,
|
services,
|
||||||
function(service, next) {
|
function(service, next) {
|
||||||
if (self._loadingServices[service.name]) {
|
if (self.services[service.name]) {
|
||||||
log.info('Stopping ' + service.name);
|
log.info('Stopping ' + service.name);
|
||||||
self._loadingServices[service.name].stop(next);
|
self.services[service.name].stop(next);
|
||||||
} else {
|
} else {
|
||||||
log.info('Stopping ' + service.name + ' (not started)');
|
log.info('Stopping ' + service.name + ' (not started)');
|
||||||
setImmediate(next);
|
setImmediate(next);
|
||||||
|
|||||||
@ -7,6 +7,7 @@ var bitcore = require('bitcore');
|
|||||||
var _ = bitcore.deps._;
|
var _ = bitcore.deps._;
|
||||||
var $ = bitcore.util.preconditions;
|
var $ = bitcore.util.preconditions;
|
||||||
var log = index.log;
|
var log = index.log;
|
||||||
|
var errors = index.errors;
|
||||||
var child_process = require('child_process');
|
var child_process = require('child_process');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var shuttingDown = false;
|
var shuttingDown = false;
|
||||||
@ -215,7 +216,10 @@ function start(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
node.start(function(err) {
|
node.start(function(err) {
|
||||||
if(err) {
|
if (err instanceof errors.Cancellation) {
|
||||||
|
log.warn('Cancelled start up of all services');
|
||||||
|
start.cleanShutdown(process, node);
|
||||||
|
} else if(err) {
|
||||||
log.error('Failed to start services');
|
log.error('Failed to start services');
|
||||||
if (err.stack) {
|
if (err.stack) {
|
||||||
log.error(err.stack);
|
log.error(err.stack);
|
||||||
|
|||||||
@ -9,6 +9,7 @@ var $ = bitcore.util.preconditions;
|
|||||||
var _ = bitcore.deps._;
|
var _ = bitcore.deps._;
|
||||||
var index = require('../');
|
var index = require('../');
|
||||||
var log = index.log;
|
var log = index.log;
|
||||||
|
var errors = index.errors;
|
||||||
var Service = require('../service');
|
var Service = require('../service');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -158,6 +159,10 @@ Bitcoin.prototype.start = function(callback) {
|
|||||||
}
|
}
|
||||||
if (self._reindex) {
|
if (self._reindex) {
|
||||||
var interval = setInterval(function() {
|
var interval = setInterval(function() {
|
||||||
|
if (self.node.pendingStop) {
|
||||||
|
clearInterval(interval);
|
||||||
|
return callback(new errors.Cancellation(), false);
|
||||||
|
}
|
||||||
var percentSynced = bindings.syncPercentage();
|
var percentSynced = bindings.syncPercentage();
|
||||||
log.info("Bitcoin Core Daemon Reindex Percentage: " + percentSynced);
|
log.info("Bitcoin Core Daemon Reindex Percentage: " + percentSynced);
|
||||||
if (percentSynced >= 100) {
|
if (percentSynced >= 100) {
|
||||||
|
|||||||
@ -324,6 +324,7 @@ describe('Bitcore Node', function() {
|
|||||||
describe('#stop', function() {
|
describe('#stop', function() {
|
||||||
it('will call stop for each service', function(done) {
|
it('will call stop for each service', function(done) {
|
||||||
var node = new Node(baseConfig);
|
var node = new Node(baseConfig);
|
||||||
|
node.started = true;
|
||||||
function TestService() {}
|
function TestService() {}
|
||||||
util.inherits(TestService, BaseService);
|
util.inherits(TestService, BaseService);
|
||||||
TestService.prototype.stop = sinon.stub().callsArg(0);
|
TestService.prototype.stop = sinon.stub().callsArg(0);
|
||||||
@ -333,10 +334,8 @@ describe('Bitcore Node', function() {
|
|||||||
['getData', this, this.getData, 1]
|
['getData', this, this.getData, 1]
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
var testService = new TestService({node: node});
|
|
||||||
node._loadingServices = {'test1': testService};
|
|
||||||
node.services = {
|
node.services = {
|
||||||
'test1': testService
|
'test1': new TestService({node: node})
|
||||||
};
|
};
|
||||||
node.test2 = {};
|
node.test2 = {};
|
||||||
node.test2.stop = sinon.stub().callsArg(0);
|
node.test2.stop = sinon.stub().callsArg(0);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user