server: Fix handling of errors during startup and shutdown
Before, an unhandled rejection or uncaught exception during startup would cause `exports.exit()` to wait forever for startup completion. Similarly, an error during shutdown would cause `exports.exit()` to wait forever for shutdown to complete. Now any error during startup or shutdown triggers an immediate exit.pull/4740/head
parent
5999d8cd44
commit
ebdb2798ff
|
@ -59,6 +59,7 @@ const State = {
|
|||
STOPPED: 5,
|
||||
EXITING: 6,
|
||||
WAITING_FOR_EXIT: 7,
|
||||
STATE_TRANSITION_FAILED: 8,
|
||||
};
|
||||
|
||||
let state = State.INITIAL;
|
||||
|
@ -85,13 +86,15 @@ exports.start = async () => {
|
|||
break;
|
||||
case State.STARTING:
|
||||
await startDoneGate;
|
||||
// fall through
|
||||
// Retry. Don't fall through because it might have transitioned to STATE_TRANSITION_FAILED.
|
||||
return await exports.start();
|
||||
case State.RUNNING:
|
||||
return express.server;
|
||||
case State.STOPPING:
|
||||
case State.STOPPED:
|
||||
case State.EXITING:
|
||||
case State.WAITING_FOR_EXIT:
|
||||
case State.STATE_TRANSITION_FAILED:
|
||||
throw new Error('restart not supported');
|
||||
default:
|
||||
throw new Error(`unknown State: ${state.toString()}`);
|
||||
|
@ -99,7 +102,7 @@ exports.start = async () => {
|
|||
logger.info('Starting Etherpad...');
|
||||
startDoneGate = new Gate();
|
||||
state = State.STARTING;
|
||||
|
||||
try {
|
||||
// Check if Etherpad version is up-to-date
|
||||
UpdateCheck.check();
|
||||
|
||||
|
@ -141,6 +144,12 @@ exports.start = async () => {
|
|||
logger.debug(`Installed hooks:\n${plugins.formatHooks()}`);
|
||||
await hooks.aCallAll('loadSettings', {settings});
|
||||
await hooks.aCallAll('createServer');
|
||||
} catch (err) {
|
||||
logger.error('Error occurred while starting Etherpad');
|
||||
state = State.STATE_TRANSITION_FAILED;
|
||||
startDoneGate.resolve();
|
||||
return await exports.exit(err);
|
||||
}
|
||||
|
||||
logger.info('Etherpad is running');
|
||||
state = State.RUNNING;
|
||||
|
@ -166,6 +175,7 @@ exports.stop = async () => {
|
|||
case State.STOPPED:
|
||||
case State.EXITING:
|
||||
case State.WAITING_FOR_EXIT:
|
||||
case State.STATE_TRANSITION_FAILED:
|
||||
return;
|
||||
default:
|
||||
throw new Error(`unknown State: ${state.toString()}`);
|
||||
|
@ -173,6 +183,7 @@ exports.stop = async () => {
|
|||
logger.info('Stopping Etherpad...');
|
||||
let stopDoneGate = new Gate();
|
||||
state = State.STOPPING;
|
||||
try {
|
||||
let timeout = null;
|
||||
await Promise.race([
|
||||
hooks.aCallAll('shutdown'),
|
||||
|
@ -181,6 +192,12 @@ exports.stop = async () => {
|
|||
}),
|
||||
]);
|
||||
clearTimeout(timeout);
|
||||
} catch (err) {
|
||||
logger.error('Error occurred while stopping Etherpad');
|
||||
state = State.STATE_TRANSITION_FAILED;
|
||||
stopDoneGate.resolve();
|
||||
return await exports.exit(err);
|
||||
}
|
||||
logger.info('Etherpad stopped');
|
||||
state = State.STOPPED;
|
||||
stopDoneGate.resolve();
|
||||
|
@ -214,6 +231,7 @@ exports.exit = async (err = null) => {
|
|||
return await exports.exit();
|
||||
case State.INITIAL:
|
||||
case State.STOPPED:
|
||||
case State.STATE_TRANSITION_FAILED:
|
||||
break;
|
||||
case State.EXITING:
|
||||
await exitGate;
|
||||
|
|
Loading…
Reference in New Issue