Application: make start/stop sturdier, catch more stop signals
This commit is contained in:
parent
93e79984e3
commit
f91bd6851f
@ -29,6 +29,8 @@ export default abstract class Application implements Extendable<ApplicationCompo
|
||||
private cacheProvider?: CacheProvider;
|
||||
|
||||
private ready: boolean = false;
|
||||
private started: boolean = false;
|
||||
private busy: boolean = false;
|
||||
|
||||
protected constructor(version: string, ignoreCommandLine: boolean = false) {
|
||||
this.version = version;
|
||||
@ -59,6 +61,10 @@ export default abstract class Application implements Extendable<ApplicationCompo
|
||||
}
|
||||
|
||||
public async start(): Promise<void> {
|
||||
if (this.started) throw new Error('Application already started');
|
||||
if (this.busy) throw new Error('Application busy');
|
||||
this.busy = true;
|
||||
|
||||
// Load core version
|
||||
const file = this.isInNodeModules() ?
|
||||
path.join(__dirname, '../../package.json') :
|
||||
@ -73,22 +79,28 @@ export default abstract class Application implements Extendable<ApplicationCompo
|
||||
logger.info(`${config.get('app.name')} v${this.version} | swaf v${this.coreVersion}`);
|
||||
|
||||
// Catch interrupt signals
|
||||
process.once('SIGINT', () => {
|
||||
const exitHandler = () => {
|
||||
this.stop().catch(console.error);
|
||||
});
|
||||
};
|
||||
process.once('exit', exitHandler);
|
||||
process.once('SIGINT', exitHandler);
|
||||
process.once('SIGUSR1', exitHandler);
|
||||
process.once('SIGUSR2', exitHandler);
|
||||
process.once('uncaughtException', exitHandler);
|
||||
|
||||
// Register migrations
|
||||
MysqlConnectionManager.registerMigrations(this.getMigrations());
|
||||
|
||||
// Process command line
|
||||
if (!this.ignoreCommandLine && await this.processCommandLine()) {
|
||||
await this.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// Register all components and alike
|
||||
await this.init();
|
||||
|
||||
// Process command line
|
||||
if (!this.ignoreCommandLine && await this.processCommandLine()) {
|
||||
this.started = true;
|
||||
this.busy = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Security
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
await this.checkSecuritySettings();
|
||||
@ -203,26 +215,54 @@ export default abstract class Application implements Extendable<ApplicationCompo
|
||||
this.routes(initRouter, handleRouter);
|
||||
|
||||
this.ready = true;
|
||||
this.started = true;
|
||||
this.busy = false;
|
||||
}
|
||||
|
||||
protected async processCommandLine(): Promise<boolean> {
|
||||
const args = process.argv;
|
||||
// Flags
|
||||
const flags = {
|
||||
verbose: false,
|
||||
fullHttpRequests: false,
|
||||
};
|
||||
let mainCommand: string | null = null;
|
||||
const mainCommandArgs: string[] = [];
|
||||
for (let i = 2; i < args.length; i++) {
|
||||
switch (args[i]) {
|
||||
case '--verbose':
|
||||
logger.setSettings({minLevel: "trace"});
|
||||
flags.verbose = true;
|
||||
break;
|
||||
case '--full-http-requests':
|
||||
LogRequestsComponent.logFullHttpRequests();
|
||||
flags.fullHttpRequests = true;
|
||||
break;
|
||||
case 'migration':
|
||||
await MysqlConnectionManager.migrationCommand(args.slice(i + 1));
|
||||
return true;
|
||||
if (mainCommand === null) mainCommand = args[i];
|
||||
else throw new Error(`Only one main command can be used at once (${mainCommand},${args[i]})`);
|
||||
break;
|
||||
default:
|
||||
logger.warn('Unrecognized argument', args[i]);
|
||||
if (mainCommand) mainCommandArgs.push(args[i]);
|
||||
else logger.fatal('Unrecognized argument', args[i]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags.verbose) logger.setSettings({minLevel: "trace"});
|
||||
if (flags.fullHttpRequests) LogRequestsComponent.logFullHttpRequests();
|
||||
|
||||
if (mainCommand) {
|
||||
switch (mainCommand) {
|
||||
case 'migration':
|
||||
await MysqlConnectionManager.migrationCommand(mainCommandArgs);
|
||||
await this.stop();
|
||||
break;
|
||||
default:
|
||||
logger.fatal('Unimplemented main command', mainCommand);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -247,13 +287,18 @@ export default abstract class Application implements Extendable<ApplicationCompo
|
||||
}
|
||||
|
||||
public async stop(): Promise<void> {
|
||||
logger.info('Stopping application...');
|
||||
if (this.started && !this.busy) {
|
||||
this.busy = true;
|
||||
logger.info('Stopping application...');
|
||||
|
||||
for (const component of this.components) {
|
||||
await component.stop?.();
|
||||
for (const component of this.components) {
|
||||
await component.stop?.();
|
||||
}
|
||||
|
||||
logger.info(`${this.constructor.name} stopped properly.`);
|
||||
this.started = false;
|
||||
this.busy = false;
|
||||
}
|
||||
|
||||
logger.info(`${this.constructor.name} v${this.version} - bye`);
|
||||
}
|
||||
|
||||
private routes(initRouter: Router, handleRouter: Router) {
|
||||
|
Loading…
Reference in New Issue
Block a user