From d23754ad9ff7527709ef9a8c811a89ddfc993fc6 Mon Sep 17 00:00:00 2001 From: Niels Vandekeybus Date: Mon, 10 Jul 2023 16:35:55 +0200 Subject: [PATCH 1/4] make boot.sh run as process 0 we want boot.sh to correctly receive and forwards signals. this commit removes the double indirection (`CMD` in non array form will already execute the command in a sh subshell and we wrapped our script in another one). --- Dockerfile | 2 +- boot.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index fac093c..9bc8f0a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,7 @@ RUN chmod +x /usr/src/app/build-production.sh EXPOSE ${PORT} -CMD sh boot.sh +CMD ["/usr/src/app/boot.sh"] # This stuff only runs when building an image from the template ONBUILD RUN rm -Rf /app/scripts diff --git a/boot.sh b/boot.sh index 20961a6..c4efb38 100755 --- a/boot.sh +++ b/boot.sh @@ -1,3 +1,4 @@ +#!/usr/bin/env bash if [ "$NODE_ENV" == "development" ] then # Run live-reload development From 3c359c6507e9bb40a32921d8bdff0bcc2353d07e Mon Sep 17 00:00:00 2001 From: Aad Versteden Date: Fri, 22 Sep 2023 13:43:00 +0200 Subject: [PATCH 2/4] Experimental fast stopping of the service --- README.md | 1 + helpers/mu/index.js | 3 ++- helpers/mu/server.js | 15 ++++++++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0083f7a..283dc91 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ The following importable variables are available: - `sparqlEscapeDateTime(value) => string`: Function to escape a datetime in SPARQL - `sparqlEscapeBool(value) => string`: Function to escape a boolean in SPARQL. The given value is evaluated to a boolean value in javascript. E.g. the string value `'0'` evaluates to `false` in javascript. - `sparqlEscape(value, type) => string`: Function to escape a value in SPARQL according to the given type. Type must be one of `'string'`, `'uri'`, `'int'`, `'float'`, `'date'`, `'dateTime'`, `'bool'`. + - `setExitHandler`: *experimental* Sets a function to be ran on exit. The default implementation executes `process.exit` which allows for fast exiting of the service and therefore also fast restarts. You can either import specific attributes from the mu library, or import the whole mu object. diff --git a/helpers/mu/index.js b/helpers/mu/index.js index 54b0c0d..6a77811 100644 --- a/helpers/mu/index.js +++ b/helpers/mu/index.js @@ -53,7 +53,8 @@ export { sparqlEscapeDateTime, sparqlEscapeBool, uuid, - errorHandler + errorHandler, + setExitHandler }; export default mu; diff --git a/helpers/mu/server.js b/helpers/mu/server.js index 9ff7aeb..0256be6 100644 --- a/helpers/mu/server.js +++ b/helpers/mu/server.js @@ -36,6 +36,18 @@ const errorHandler = function(err, req, res, next) { }); }; +// faster stopping +let exitHandler = function() { + return process.exit(); +}; + +process.on('SIGTERM', exitHandler ); +process.on('SIGINT', exitHandler ); + +function setExitHandler( functor ) { + this.exitHandler = functor; +} + // start server app.listen( port, hostname, function() { console.log(`Starting server on ${hostname}:${port} in ${app.get('env')} mode`); @@ -45,5 +57,6 @@ export default app; export { app, - errorHandler + errorHandler, + setExitHandler } From 7fb5ae55d53fe914b3f3c2a05e78a3eb2da8b16f Mon Sep 17 00:00:00 2001 From: Aad Versteden Date: Fri, 22 Sep 2023 17:36:46 +0200 Subject: [PATCH 3/4] Import setExitHandler before exporting We only exported setExitHandler but that doesn't do much when we don't import it first. --- helpers/mu/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/mu/index.js b/helpers/mu/index.js index 6a77811..3dd84ed 100644 --- a/helpers/mu/index.js +++ b/helpers/mu/index.js @@ -1,4 +1,4 @@ -import { app, errorHandler } from './server'; +import { app, errorHandler, setExitHandler } from './server'; import sparql from './sparql'; import { v1 as uuidV1 } from 'uuid'; From 5f86d226fb12b6f5ee7f4c6868b0a05fbc32e958 Mon Sep 17 00:00:00 2001 From: Aad Versteden Date: Fri, 22 Sep 2023 17:37:14 +0200 Subject: [PATCH 4/4] Updated default exitHandler Here is a new exitHandler based on @nvdk's suggestions and research. It doesn't fully behave the way we intend (the last message is not logged) but does further serve as a proof of concept. --- helpers/mu/server.js | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/helpers/mu/server.js b/helpers/mu/server.js index 0256be6..d8b9f87 100644 --- a/helpers/mu/server.js +++ b/helpers/mu/server.js @@ -36,22 +36,33 @@ const errorHandler = function(err, req, res, next) { }); }; + +// start server +const server = app.listen( port, hostname, function() { + console.log(`Starting server on ${hostname}:${port} in ${app.get('env')} mode`); +}); + // faster stopping -let exitHandler = function() { - return process.exit(); +let exitHandler = function(server) { + console.debug("Preparing to shut down"); + server.close( () => { + console.debug("Shut down complete"); + }); }; -process.on('SIGTERM', exitHandler ); -process.on('SIGINT', exitHandler ); - +/** + * Sets a new handler for shutting down the server. + * + * @arg functor Function taking one argument (the result of app.listen + * when starting the server) which should gracefully stop the server. + */ function setExitHandler( functor ) { this.exitHandler = functor; } -// start server -app.listen( port, hostname, function() { - console.log(`Starting server on ${hostname}:${port} in ${app.get('env')} mode`); -}); +process.on('SIGTERM', () => exitHandler(server) ); +process.on('SIGINT', () => exitHandler(server) ); + export default app;