MCPcopy Create free account
hub / github.com/Openpanel-dev/openpanel / shutdown

Function shutdown

apps/api/src/utils/graceful-shutdown.ts:30–139  ·  view source on GitHub ↗
(
  fastify: FastifyInstance,
  signal: string,
  exitCode = 0
)

Source from the content-addressed store, hash-verified

28
29// Graceful shutdown handler
30export async function shutdown(
31 fastify: FastifyInstance,
32 signal: string,
33 exitCode = 0
34) {
35 if (isShuttingDown()) {
36 logger.warn({ signal }, 'Shutdown already in progress, ignoring signal');
37 return;
38 }
39
40 logger.info({ signal }, 'Starting graceful shutdown');
41
42 setShuttingDown(true);
43
44 // Hard deadline: if any close() below hangs (Kafka producer stuck,
45 // Redis still connecting, BullMQ wait), force-exit before Docker's
46 // stop_grace_period elapses. Without this the container can sit in
47 // "Stopping" until SIGKILL (exit 137) and look like a real crash.
48 const forceExitMs = Number(process.env.SHUTDOWN_FORCE_EXIT_MS || '15000');
49 const forceExit = setTimeout(() => {
50 logger.error(
51 { signal, forceExitMs },
52 'Graceful shutdown timed out — forcing exit',
53 );
54 process.exit(exitCode);
55 }, forceExitMs);
56 forceExit.unref();
57
58 // Step 1: Wait for load balancer to stop sending traffic (matches preStop sleep)
59 const gracePeriod = Number(process.env.SHUTDOWN_GRACE_PERIOD_MS || '5000');
60 await new Promise((resolve) => setTimeout(resolve, gracePeriod));
61
62 // Step 2: Close Fastify to drain in-flight requests
63 try {
64 await fastify.close();
65 logger.info('Fastify server closed');
66 } catch (error) {
67 logger.error({ err: error }, 'Error closing Fastify server');
68 }
69
70 // Step 3: Destroy MCP sessions
71 try {
72 await mcpSessionManager.destroy();
73 logger.info('MCP sessions closed');
74 } catch (error) {
75 logger.error({ err: error }, 'Error closing MCP sessions');
76 }
77
78 // Step 4: Close database connections
79 try {
80 await db.$disconnect();
81 logger.info('Database connection closed');
82 } catch (error) {
83 logger.error({ err: error }, 'Error closing database connection');
84 }
85
86 // Step 5: Close ClickHouse connections
87 try {

Callers 1

startServerFunction · 0.90

Calls 13

disconnectKafkaFunction · 0.90
getRedisCacheFunction · 0.90
getRedisPubFunction · 0.90
getRedisSubFunction · 0.90
getRedisQueueFunction · 0.90
infoMethod · 0.80
closeMethod · 0.80
isShuttingDownFunction · 0.70
setShuttingDownFunction · 0.70
warnMethod · 0.45
errorMethod · 0.45
destroyMethod · 0.45

Tested by

no test coverage detected