fullnode: reemit abort and let bin handle the shutdown.

This commit is contained in:
Nodari Chkuaselidze 2022-06-03 17:34:56 +04:00 committed by Matthew Zipkin
parent 4c665cb42b
commit ee5d45fa31
No known key found for this signature in database
GPG key ID: E7E2984B6289C93A
8 changed files with 81 additions and 64 deletions

View file

@ -50,6 +50,26 @@ process.on('SIGINT', async () => {
await node.close();
});
node.on('abort', async (err) => {
const timeout = setTimeout(() => {
console.error('Shutdown is taking a long time. Exitting.');
process.exit(3);
}, 5000);
timeout.unref();
try {
console.error('Shutting down...');
await node.close();
clearTimeout(timeout);
console.error(err.stack);
process.exit(2);
} catch (e) {
console.error(`Error occurred during shutdown: ${e.message}`);
process.exit(3);
}
});
(async () => {
await node.ensure();
await node.open();

View file

@ -67,6 +67,26 @@ process.on('SIGINT', async () => {
await node.close();
});
node.on('abort', async (err) => {
const timeout = setTimeout(() => {
console.error('Shutdown is taking a long time. Exitting.');
process.exit(3);
}, 5000);
timeout.unref();
try {
console.error('Shutting down...');
await node.close();
clearTimeout(timeout);
console.error(err.stack);
process.exit(2);
} catch (e) {
console.error(`Error occurred during shutdown: ${e.message}`);
process.exit(3);
}
});
(async () => {
await node.ensure();
await node.open();

View file

@ -998,8 +998,9 @@ class Chain extends AsyncEmitter {
if (ns.isNull()) {
if (!covenant.isClaim() && !covenant.isOpen()) {
this.emit('abort', 'Unexpected null NameState.');
throw new CriticalError('Database inconsistency.');
const error = new CriticalError('Database inconsistency.');
this.emit('abort', error);
throw error;
}
const name = covenant.get(2);
@ -1899,8 +1900,9 @@ class Chain extends AsyncEmitter {
try {
await this.db.save(entry, block, view);
} catch (e) {
this.emit('abort', e.message);
throw new CriticalError(e);
const error = new CriticalError(e.message);
this.emit('abort', error);
throw error;
}
// Expose the new state.
@ -1963,8 +1965,9 @@ class Chain extends AsyncEmitter {
try {
await this.db.save(entry, block);
} catch (e) {
this.emit('abort', e.message);
throw new CriticalError(e);
const error = new CriticalError(e.message);
this.emit('abort', error);
throw error;
}
this.logger.warning('Heads up: Competing chain at height %d:'

View file

@ -10,43 +10,24 @@
* @module errors
*/
const assert = require('bsert');
/**
* Critical Error
* An error severe enough to warrant shutting down the node.
* @extends Error
* @param {Block|TX} msg
* @param {String} code - Reject packet code.
* @param {String} reason - Reject packet reason.
* @param {Number} score - Ban score increase
* (can be -1 for no reject packet).
* @param {Boolean} malleated
*/
class CriticalError extends Error {
/**
* Create a verify error.
* @constructor
* @param {Block|TX} msg
* @param {String} code - Reject packet code.
* @param {String} reason - Reject packet reason.
* @param {Number} score - Ban score increase
* (can be -1 for no reject packet).
* @param {Boolean} malleated
* @param {String} msg
*/
constructor(err) {
constructor(msg) {
super();
this.type = 'CriticalError';
if (err instanceof Error) {
this.message = `Critical Error: ${err.message}`;
} else {
assert(typeof err === 'string');
this.message = `Critical Error: ${err}`;
}
this.message = `Critical Error: ${msg}`;
if (Error.captureStackTrace)
Error.captureStackTrace(this, CriticalError);

View file

@ -197,7 +197,7 @@ class FullNode extends Node {
init() {
// Bind to errors
this.chain.on('error', err => this.error(err));
this.chain.on('abort', msg => this.abort(msg));
this.chain.on('abort', err => this.abort(err));
this.mempool.on('error', err => this.error(err));
this.pool.on('error', err => this.error(err));
@ -350,23 +350,6 @@ class FullNode extends Node {
this.emit('closed');
}
/**
* Emergency shutdown.
* @param {String} msg - error message
* @returns {Promise}
*/
async abort(msg) {
this.logger.error(`Critical error, shutting down: ${msg}`);
try {
this.emit('abort', msg);
await this.close();
} catch (e) {
this.logger.error(`Error occurred during shutdown: ${e.message}`);
process.exit(-2);
}
}
/**
* Rescan for any missed transactions.
* @param {Number|Hash} start - Start block.

View file

@ -305,6 +305,17 @@ class Node extends EventEmitter {
this.emit('error', err);
}
/**
* Emit and log an abort error.
* @private
* @param {Error} err
*/
abort(err) {
this.logger.error(err);
this.emit('abort', err);
}
/**
* Get node uptime in seconds.
* @returns {Number}

View file

@ -130,7 +130,7 @@ class SPVNode extends Node {
init() {
// Bind to errors
this.chain.on('error', err => this.error(err));
this.chain.on('abort', msg => this.abort(msg));
this.chain.on('abort', err => this.abort(err));
this.pool.on('error', err => this.error(err));
@ -221,23 +221,6 @@ class SPVNode extends Node {
this.emit('closed');
}
/**
* Emergency shutdown.
* @param {String} msg - error message
* @returns {Promise}
*/
async abort(msg) {
this.logger.error(`Critical error, shutting down: ${msg}`);
try {
this.emit('abort', msg);
await this.close();
} catch (e) {
this.logger.error(`Error occurred during shutdown: ${e.message}`);
process.exit(-2);
}
}
/**
* Scan for any missed transactions.
* Note that this will replay the blockchain sync.

View file

@ -88,6 +88,14 @@ describe('Node Critical Error', function() {
node.once('closed', () => resolve());
});
node.on('abort', async () => {
try {
await node.close();
} catch (e) {
;
}
});
await mineBlocks(node, 99);
node.chain.db.db.batch = () => {
return {
@ -112,6 +120,14 @@ describe('Node Critical Error', function() {
node.once('closed', () => resolve());
});
node.on('abort', async () => {
try {
await node.close();
} catch (e) {
;
}
});
await mineBlocks(node, 50);
node.chain.db.tree.store.commit = () => {
throw new Error('Disk full!');