diff --git a/packages/server/src/launcher.ts b/packages/server/src/launcher.ts index 1920a7cac..2bf87e0f9 100644 --- a/packages/server/src/launcher.ts +++ b/packages/server/src/launcher.ts @@ -83,8 +83,17 @@ export class Launcher { if (!this.shuttingDown) { this.shuttingDown = true + if (!yn(process.env.SPINNED)) { + this.logger.info('Server gracefully closing down...') + } + + await this.api.sockets.destroy() await this.httpTerminator?.terminate() await this.app.destroy() + + if (!yn(process.env.SPINNED)) { + this.logger.info('Server shutdown complete') + } } process.exit(code) } diff --git a/packages/server/src/socket/manager.ts b/packages/server/src/socket/manager.ts index c946a4e0c..1dd9475b1 100644 --- a/packages/server/src/socket/manager.ts +++ b/packages/server/src/socket/manager.ts @@ -7,17 +7,38 @@ import { SocketService } from './service' export class SocketManager { private logger = new Logger('Socket') + private ws: Socket.Server | undefined private handlers: { [type: string]: SocketHandler } = {} constructor(private sockets: SocketService) {} async setup(server: Server) { if (yn(process.env.ENABLE_EXPERIMENTAL_SOCKETS)) { - const ws = new Socket.Server(server, { cors: { origin: '*' } }) - ws.on('connection', this.handleSocketConnection.bind(this)) + this.ws = new Socket.Server(server, { cors: { origin: '*' } }) + this.ws.on('connection', this.handleSocketConnection.bind(this)) } } + async destroy() { + if (!this.ws) { + return + } + + await new Promise((resolve, reject) => { + // This is kind of hack to make sure that socket.io does not + // try to close the HTTP server before http-terminator + this.ws!['httpServer'] = undefined + + this.ws!.close((err) => { + if (err) { + this.logger.error(err, 'An error occurred when closing the websocket server.') + } + + resolve(undefined) + }) + }) + } + public handle(type: string, callback: SocketHandler) { this.handlers[type] = callback }