Merge pull request #573 from embark-framework/bug_fix/blockchain-kill-causes-error

Handle geth process exit via crash/kill and also via killing `embark blockchain`
This commit is contained in:
Iuri Matias 2018-06-26 16:24:11 -04:00 committed by GitHub
commit 3bea80a820
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 67 additions and 13 deletions

View File

@ -14,6 +14,7 @@ var Blockchain = function(options) {
this.client = options.client;
this.isDev = options.isDev;
this.onReadyCallback = options.onReadyCallback;
this.onExitCallback = options.onExitCallback;
if ((this.blockchainConfig === {} || JSON.stringify(this.blockchainConfig) === '{"enabled":true}') && this.env !== 'development') {
console.log("===> " + __("warning: running default config on a non-development environment"));
@ -167,8 +168,24 @@ Blockchain.prototype.run = function() {
console.log('Geth: ' + data);
});
self.child.on('exit', (code) => {
let strCode;
if (code) {
console.error('Geth exited with error code ' + code);
strCode = ' with error code ' + code;
} else {
strCode = ' with no error code (manually killed?)';
}
console.error('Geth exited' + strCode);
if(self.onExitCallback){
self.onExitCallback();
}
});
self.child.on('uncaughtException', (err) => {
console.error('Uncaught geth exception', err);
if(self.onExitCallback){
self.onExitCallback();
}
});
});
@ -252,10 +269,10 @@ Blockchain.prototype.initChainAndGetAddress = function(callback) {
});
};
var BlockchainClient = function(blockchainConfig, client, env, isDev, onReadyCallback) {
var BlockchainClient = function(blockchainConfig, client, env, isDev, onReadyCallback, onExitCallback) {
// TODO add other clients at some point
if (client === 'geth') {
return new Blockchain({blockchainConfig, client: GethCommands, env, isDev, onReadyCallback});
return new Blockchain({blockchainConfig, client: GethCommands, env, isDev, onReadyCallback, onExitCallback});
} else {
throw new Error('unknown client');
}

View File

@ -21,7 +21,8 @@ class BlockchainProcess extends ProcessWrapper {
this.client,
this.env,
this.isDev,
this.blockchainReady.bind(this)
this.blockchainReady.bind(this),
this.blockchainExit.bind(this)
);
this.blockchain.run();
@ -31,6 +32,11 @@ class BlockchainProcess extends ProcessWrapper {
blockchainProcess.send({result: constants.blockchain.blockchainReady});
}
blockchainExit() {
// tell our parent process that geth has exited
blockchainProcess.send({result: constants.blockchain.blockchainExit});
}
kill() {
this.blockchain.kill();
}

View File

@ -34,6 +34,7 @@
},
"blockchain": {
"blockchainReady": "blockchainReady",
"blockchainExit": "blockchainExit",
"init": "init",
"initiated": "initiated",
"servicePortOnProxy": 10

View File

@ -48,7 +48,7 @@ class Blockchain {
}
const protocol = (this.contractsConfig.deployment.type === "rpc") ? this.contractsConfig.deployment.protocol : 'ws';
let provider;
this.web3Endpoint = utils.buildUrl(protocol, this.contractsConfig.deployment.host, this.contractsConfig.deployment.port);//`${protocol}://${this.contractsConfig.deployment.host}:${this.contractsConfig.deployment.port}`;
const providerOptions = {
@ -60,7 +60,7 @@ class Blockchain {
type: this.contractsConfig.deployment.type,
web3Endpoint: self.web3Endpoint
};
provider = new Provider(providerOptions);
this.provider = new Provider(providerOptions);
async.waterfall([
function checkNode(next) {
@ -73,21 +73,35 @@ class Blockchain {
if (!err) {
self.isWeb3Ready = true;
self.events.emit(WEB3_READY);
// if the ethereum node goes offline, we need a check to ensure
// the provider is also stopped
self.events.on('check:wentOffline:Ethereum', () => {
self.logger.trace('Ethereum went offline: stopping web3 provider...');
self.provider.stop();
// once the node goes back online, we can restart the provider
self.events.once('check:backOnline:Ethereum', () => {
self.logger.trace('Ethereum back online: starting web3 provider...');
self.provider.startWeb3Provider(() => {
self.logger.trace('web3 provider restarted after ethereum node came back online');
});
});
});
return next();
}
self.web3StartedInProcess = true;
self.startBlockchainNode(() => {
// Need to re-initialize web3 to connect to the new blockchain node
provider.stop();
self.provider.stop();
self.initWeb3(cb);
});
});
},
function startProvider(next) {
provider.startWeb3Provider(next);
self.provider.startWeb3Provider(next);
},
function fundAccountsIfNeeded(next) {
provider.fundAccounts(next);
self.provider.fundAccounts(next);
}
], (err) => {
self.registerWeb3Object();
@ -120,6 +134,10 @@ class Blockchain {
self.events.once(constants.blockchain.blockchainReady, () => {
callback();
});
self.events.once(constants.blockchain.blockchainExit, () => {
self.provider.stop();
callback();
});
}
registerServiceCheck() {

View File

@ -39,12 +39,16 @@ class Provider {
// network connectivity error
self.engine.on('error', (err) => {
// report connectivity errors
self.logger.error(err.stack);
// report connectivity errors as trace due to polling
self.logger.trace('web3 provider error: ', err);
self.logger.trace('stopping web3 provider due to error');
// prevent continuous polling errors
self.engine.stop();
});
self.engine.start();
self.web3.setProvider(self);
self.web3.setProvider(self);
self.accounts = AccountParser.parseAccountsConfig(self.accountsConfig, self.web3, self.logger);
self.addresses = [];

View File

@ -44,6 +44,14 @@ class BlockchainProcessLauncher {
this.events.emit(constants.blockchain.blockchainReady);
});
this.blockchainProcess.once('result', constants.blockchain.blockchainExit, () => {
// telle everyone that our blockchain process (ie geth) died
this.events.emit(constants.blockchain.blockchainExit);
// then kill off the blockchain process
this.blockchainProcess.kill();
});
this.events.on('exit', () => {
this.blockchainProcess.send('exit');
});

View File

@ -79,7 +79,7 @@
"uuid": "^3.2.1",
"viz.js": "^1.8.1",
"web3": "1.0.0-beta.34",
"embark-web3-provider-engine": "14.0.6",
"embark-web3-provider-engine": "14.0.7",
"webpack": "^3.10.0",
"window-size": "^1.1.0"
},