From 90169fbd23f8f7c848e0edaa075562e7c4395c37 Mon Sep 17 00:00:00 2001 From: hfuss Date: Fri, 2 Jul 2021 11:25:24 -0400 Subject: [PATCH 1/2] Graceful Shutdown for Cloud-Native Environments Signed-off-by: hfuss --- src/app.ts | 8 +++++++- src/index.ts | 8 ++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/app.ts b/src/app.ts index e85970c..beadcf7 100644 --- a/src/app.ts +++ b/src/app.ts @@ -141,7 +141,13 @@ export const start = async () => { const apiServerPromise = new Promise(resolve => apiServer.listen(config.api.port, config.api.hostname, () => resolve())); const p2pServerPromise = new Promise(resolve => p2pServer.listen(config.p2p.port, config.p2p.hostname, () => resolve())); await Promise.all([apiServerPromise, p2pServerPromise]); - log.info(`Data exchange running on http://${config.api.hostname}:${config.api.port} (API) and ` + + log.info(`FireFly Data Exchange running on http://${config.api.hostname}:${config.api.port} (API) and ` + `https://${config.p2p.hostname}:${config.p2p.port} (P2P) - log level "${utils.constants.LOG_LEVEL}"`); }; + +export const stop = async () => { + // add any additional logic for ensuring clients and handlers are finished with their work before shutting down + log.info("FireFly Data Exchange is gracefully shutting down"); + process.exit(); +}; diff --git a/src/index.ts b/src/index.ts index 836b903..8f82e16 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,11 +14,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { start } from './app'; +import { start, stop } from './app'; import { Logger } from './lib/logger'; const log = new Logger("index.ts") +process.on('SIGINT', stop); +process.on('SIGTERM', stop); +process.on('SIGQUIT', stop); + start().catch(err => { - log.error(`Failed to FireFly Data Exchange ${err}`); + log.error(`Failed to start FireFly Data Exchange ${err}`); }); From 067a9247ed99f86ea9065bf00bda11b97e637e66 Mon Sep 17 00:00:00 2001 From: hfuss Date: Fri, 2 Jul 2021 12:13:51 -0400 Subject: [PATCH 2/2] Ensuring all webservers are stopped before exiting Signed-off-by: hfuss --- src/app.ts | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/app.ts b/src/app.ts index beadcf7..21372cd 100644 --- a/src/app.ts +++ b/src/app.ts @@ -16,7 +16,7 @@ import express from 'express'; import http from 'http'; -import https, { Server } from 'https'; +import https from 'https'; import path from 'path'; import swaggerUi from 'swagger-ui-express'; import WebSocket from 'ws'; @@ -36,7 +36,9 @@ const log = new Logger("app.ts"); const swaggerDocument = YAML.load(path.join(__dirname, './swagger.yaml')); -let p2pServer : Server +let p2pServer : https.Server +let apiServer : http.Server +let wss : WebSocket.Server let delegatedWebSocket: WebSocket | undefined = undefined; @@ -51,12 +53,12 @@ export const start = async () => { await initCert(); const apiApp = express(); - const apiServer = http.createServer(apiApp); + apiServer = http.createServer(apiApp); const p2pApp = express(); p2pServer = https.createServer(genTLSContext(), p2pApp); - const wss = new WebSocket.Server({ + wss = new WebSocket.Server({ server: apiServer, verifyClient: (info, cb) => { if (config.api === undefined || info.req.headers['x-api-key'] === config.apiKey) { cb(true); @@ -146,8 +148,23 @@ export const start = async () => { }; +const shutdownHandler = (resolve : (value: void | PromiseLike) => void) => { + return (err: Error | undefined) => { + if (err === undefined) { + resolve(); + } else { + log.error(`Failed to close server due to ${err}`); + } + }; +}; + export const stop = async () => { // add any additional logic for ensuring clients and handlers are finished with their work before shutting down - log.info("FireFly Data Exchange is gracefully shutting down"); + log.info("FireFly Data Exchange is gracefully shutting down the webservers"); + const apiServerPromise = new Promise(resolve => apiServer.close( shutdownHandler(resolve))); + const p2pServerPromise = new Promise(resolve => p2pServer.close( shutdownHandler(resolve))); + const wssPromise = new Promise(resolve => wss.close(shutdownHandler(resolve))); + await Promise.all([apiServerPromise, p2pServerPromise, wssPromise]); + log.info("FireFly Data Exchange has stopped all webservers, exiting"); process.exit(); };