@ecdt/server-common 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/index.js +2 -1
- package/src/services/shutdownService.js +58 -0
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const bodyParser = require("body-parser");
|
|
2
2
|
const { devMktTokenSanitaze } = require("./services/tokenService.js");
|
|
3
3
|
const { expressCors } = require("./services/corsService.js");
|
|
4
|
+
const { setupGracefulShutdown } = require("./services/shutdownService.js");
|
|
4
5
|
|
|
5
6
|
function expressCommonMiddlewares({ cookieName } = {}){
|
|
6
7
|
return [bodyParser.text(), bodyParser.json(), bodyParser.urlencoded({extended: false}), devMktTokenSanitaze({ cookieName })];
|
|
@@ -9,4 +10,4 @@ function expressCommonMiddlewares({ cookieName } = {}){
|
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
|
|
12
|
-
module.exports = { expressCommonMiddlewares, expressCors }
|
|
13
|
+
module.exports = { expressCommonMiddlewares, expressCors, setupGracefulShutdown }
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graceful shutdown padrão dos microsserviços da Econodata em Kubernetes.
|
|
3
|
+
* Extraído do dev-mkt-busca: o preStop (20s) já tirou o pod do EndpointSlice
|
|
4
|
+
* antes do SIGTERM, então aqui só drenamos as conexões em voo e encerramos o
|
|
5
|
+
* processo antes do SIGKILL.
|
|
6
|
+
*
|
|
7
|
+
* @param {import('http').Server} server - servidor retornado por http.createServer(app).listen(...) ou app.listen(...)
|
|
8
|
+
* @param {object} [options]
|
|
9
|
+
* @param {() => (Promise<void>|void)} [options.onShutdown] - cleanup extra (fechar pools, Redis, etc.) executado após o server fechar
|
|
10
|
+
* @param {number} [options.failsafeTimeoutMs] - tempo máximo do graceful antes de forçar a saída (default 10s: grace 40s − 20s de preStop)
|
|
11
|
+
*/
|
|
12
|
+
function setupGracefulShutdown(server, { onShutdown, failsafeTimeoutMs = 10 * 1000 } = {}) {
|
|
13
|
+
let shuttingDown = false;
|
|
14
|
+
const gracefulShutdown = signal => {
|
|
15
|
+
if (shuttingDown) return;
|
|
16
|
+
shuttingDown = true;
|
|
17
|
+
console.warn(JSON.stringify({
|
|
18
|
+
severity: 'WARNING',
|
|
19
|
+
message: `[shutdown] ${signal} recebido — encerrando`,
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
server.close(async err => {
|
|
23
|
+
if (err) {
|
|
24
|
+
console.error('[shutdown] Erro ao fechar o server HTTP:', err.message || err);
|
|
25
|
+
} else {
|
|
26
|
+
console.warn(JSON.stringify({
|
|
27
|
+
severity: 'WARNING',
|
|
28
|
+
message: '[shutdown] Server HTTP fechado, conexões em voo drenadas',
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
if (onShutdown) {
|
|
32
|
+
try {
|
|
33
|
+
await onShutdown();
|
|
34
|
+
} catch (cleanupErr) {
|
|
35
|
+
console.warn(JSON.stringify({
|
|
36
|
+
severity: 'WARNING',
|
|
37
|
+
message: `[shutdown] Falha no cleanup: ${cleanupErr.message || cleanupErr}`,
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
process.exit(err ? 1 : 0);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// fecha conexões keep-alive ociosas, senão um keepAliveTimeout alto segura o close()
|
|
45
|
+
server.closeIdleConnections();
|
|
46
|
+
|
|
47
|
+
// failsafe antes do SIGKILL (grace 40s − 20s de preStop)
|
|
48
|
+
setTimeout(() => {
|
|
49
|
+
console.error('[shutdown] Timeout no graceful shutdown, forçando saída');
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}, failsafeTimeoutMs).unref();
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
|
55
|
+
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = { setupGracefulShutdown };
|