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.client = options.client;
this.isDev = options.isDev; this.isDev = options.isDev;
this.onReadyCallback = options.onReadyCallback; this.onReadyCallback = options.onReadyCallback;
this.onExitCallback = options.onExitCallback;
if ((this.blockchainConfig === {} || JSON.stringify(this.blockchainConfig) === '{"enabled":true}') && this.env !== 'development') { if ((this.blockchainConfig === {} || JSON.stringify(this.blockchainConfig) === '{"enabled":true}') && this.env !== 'development') {
console.log("===> " + __("warning: running default config on a non-development environment")); console.log("===> " + __("warning: running default config on a non-development environment"));
@ -167,8 +168,24 @@ Blockchain.prototype.run = function() {
console.log('Geth: ' + data); console.log('Geth: ' + data);
}); });
self.child.on('exit', (code) => { self.child.on('exit', (code) => {
let strCode;
if (code) { 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 // TODO add other clients at some point
if (client === 'geth') { if (client === 'geth') {
return new Blockchain({blockchainConfig, client: GethCommands, env, isDev, onReadyCallback}); return new Blockchain({blockchainConfig, client: GethCommands, env, isDev, onReadyCallback, onExitCallback});
} else { } else {
throw new Error('unknown client'); throw new Error('unknown client');
} }

View File

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

View File

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

View File

@ -48,7 +48,7 @@ class Blockchain {
} }
const protocol = (this.contractsConfig.deployment.type === "rpc") ? this.contractsConfig.deployment.protocol : 'ws'; 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}`; this.web3Endpoint = utils.buildUrl(protocol, this.contractsConfig.deployment.host, this.contractsConfig.deployment.port);//`${protocol}://${this.contractsConfig.deployment.host}:${this.contractsConfig.deployment.port}`;
const providerOptions = { const providerOptions = {
@ -60,7 +60,7 @@ class Blockchain {
type: this.contractsConfig.deployment.type, type: this.contractsConfig.deployment.type,
web3Endpoint: self.web3Endpoint web3Endpoint: self.web3Endpoint
}; };
provider = new Provider(providerOptions); this.provider = new Provider(providerOptions);
async.waterfall([ async.waterfall([
function checkNode(next) { function checkNode(next) {
@ -73,21 +73,35 @@ class Blockchain {
if (!err) { if (!err) {
self.isWeb3Ready = true; self.isWeb3Ready = true;
self.events.emit(WEB3_READY); 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(); return next();
} }
self.web3StartedInProcess = true; self.web3StartedInProcess = true;
self.startBlockchainNode(() => { self.startBlockchainNode(() => {
// Need to re-initialize web3 to connect to the new blockchain node // Need to re-initialize web3 to connect to the new blockchain node
provider.stop(); self.provider.stop();
self.initWeb3(cb); self.initWeb3(cb);
}); });
}); });
}, },
function startProvider(next) { function startProvider(next) {
provider.startWeb3Provider(next); self.provider.startWeb3Provider(next);
}, },
function fundAccountsIfNeeded(next) { function fundAccountsIfNeeded(next) {
provider.fundAccounts(next); self.provider.fundAccounts(next);
} }
], (err) => { ], (err) => {
self.registerWeb3Object(); self.registerWeb3Object();
@ -120,6 +134,10 @@ class Blockchain {
self.events.once(constants.blockchain.blockchainReady, () => { self.events.once(constants.blockchain.blockchainReady, () => {
callback(); callback();
}); });
self.events.once(constants.blockchain.blockchainExit, () => {
self.provider.stop();
callback();
});
} }
registerServiceCheck() { registerServiceCheck() {

View File

@ -39,12 +39,16 @@ class Provider {
// network connectivity error // network connectivity error
self.engine.on('error', (err) => { self.engine.on('error', (err) => {
// report connectivity errors // report connectivity errors as trace due to polling
self.logger.error(err.stack); 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.engine.start();
self.web3.setProvider(self); self.web3.setProvider(self);
self.accounts = AccountParser.parseAccountsConfig(self.accountsConfig, self.web3, self.logger); self.accounts = AccountParser.parseAccountsConfig(self.accountsConfig, self.web3, self.logger);
self.addresses = []; self.addresses = [];

View File

@ -44,6 +44,14 @@ class BlockchainProcessLauncher {
this.events.emit(constants.blockchain.blockchainReady); 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.events.on('exit', () => {
this.blockchainProcess.send('exit'); this.blockchainProcess.send('exit');
}); });

View File

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