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);
|
||||
Transaction.NotFound = createError('NotFound', Transaction);
|
||||
|
||||
var Cancellation = createError('Cancellation', BitcoreNodeError);
|
||||
|
||||
module.exports = {
|
||||
Error: BitcoreNodeError,
|
||||
NoOutputs: NoOutputs,
|
||||
NoOutput: NoOutput,
|
||||
Wallet: Wallet,
|
||||
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.services = {};
|
||||
this._unloadedServices = [];
|
||||
this._loadingServices = {};
|
||||
this.started = false;
|
||||
|
||||
// TODO type check the arguments of config.services
|
||||
if (config.services) {
|
||||
@ -141,16 +141,15 @@ Node.prototype._startService = function(serviceInfo, callback) {
|
||||
config.node = this;
|
||||
config.name = serviceInfo.name;
|
||||
var service = new serviceInfo.module(config);
|
||||
self._loadingServices[service.name] = service;
|
||||
|
||||
// include in loaded services
|
||||
self.services[serviceInfo.name] = service;
|
||||
|
||||
service.start(function(err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// include in loaded services
|
||||
self.services[serviceInfo.name] = service;
|
||||
|
||||
// add API methods
|
||||
var methodData = service.getAPIMethods();
|
||||
var methodNameConflicts = [];
|
||||
@ -188,16 +187,24 @@ Node.prototype.start = function(callback) {
|
||||
self._startService(service, next);
|
||||
},
|
||||
function(err) {
|
||||
if (err) {
|
||||
if (err instanceof errors.Cancellation) {
|
||||
self.cancellation = true;
|
||||
return callback(err);
|
||||
} else if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
self.emit('ready');
|
||||
self.started = true;
|
||||
callback();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
Node.prototype.stop = function(callback) {
|
||||
if (!this.started && !this.cancellation) {
|
||||
this.pendingStop = true;
|
||||
return;
|
||||
}
|
||||
log.info('Beginning shutdown');
|
||||
var self = this;
|
||||
var services = this.getServiceOrder().reverse();
|
||||
@ -208,9 +215,9 @@ Node.prototype.stop = function(callback) {
|
||||
async.eachSeries(
|
||||
services,
|
||||
function(service, next) {
|
||||
if (self._loadingServices[service.name]) {
|
||||
if (self.services[service.name]) {
|
||||
log.info('Stopping ' + service.name);
|
||||
self._loadingServices[service.name].stop(next);
|
||||
self.services[service.name].stop(next);
|
||||
} else {
|
||||
log.info('Stopping ' + service.name + ' (not started)');
|
||||
setImmediate(next);
|
||||
|
||||
@ -7,6 +7,7 @@ var bitcore = require('bitcore');
|
||||
var _ = bitcore.deps._;
|
||||
var $ = bitcore.util.preconditions;
|
||||
var log = index.log;
|
||||
var errors = index.errors;
|
||||
var child_process = require('child_process');
|
||||
var fs = require('fs');
|
||||
var shuttingDown = false;
|
||||
@ -215,7 +216,10 @@ function start(options) {
|
||||
});
|
||||
|
||||
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');
|
||||
if (err.stack) {
|
||||
log.error(err.stack);
|
||||
|
||||
@ -9,6 +9,7 @@ var $ = bitcore.util.preconditions;
|
||||
var _ = bitcore.deps._;
|
||||
var index = require('../');
|
||||
var log = index.log;
|
||||
var errors = index.errors;
|
||||
var Service = require('../service');
|
||||
|
||||
/**
|
||||
@ -158,6 +159,10 @@ Bitcoin.prototype.start = function(callback) {
|
||||
}
|
||||
if (self._reindex) {
|
||||
var interval = setInterval(function() {
|
||||
if (self.node.pendingStop) {
|
||||
clearInterval(interval);
|
||||
return callback(new errors.Cancellation(), false);
|
||||
}
|
||||
var percentSynced = bindings.syncPercentage();
|
||||
log.info("Bitcoin Core Daemon Reindex Percentage: " + percentSynced);
|
||||
if (percentSynced >= 100) {
|
||||
|
||||
@ -324,6 +324,7 @@ describe('Bitcore Node', function() {
|
||||
describe('#stop', function() {
|
||||
it('will call stop for each service', function(done) {
|
||||
var node = new Node(baseConfig);
|
||||
node.started = true;
|
||||
function TestService() {}
|
||||
util.inherits(TestService, BaseService);
|
||||
TestService.prototype.stop = sinon.stub().callsArg(0);
|
||||
@ -333,10 +334,8 @@ describe('Bitcore Node', function() {
|
||||
['getData', this, this.getData, 1]
|
||||
];
|
||||
};
|
||||
var testService = new TestService({node: node});
|
||||
node._loadingServices = {'test1': testService};
|
||||
node.services = {
|
||||
'test1': testService
|
||||
'test1': new TestService({node: node})
|
||||
};
|
||||
node.test2 = {};
|
||||
node.test2.stop = sinon.stub().callsArg(0);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user