feat: add graceful shutdown handling (SIGTERM/SIGINT)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-03-23 09:13:04 +01:00
parent 5b56fc4dff
commit 6618ef1abd

View File

@@ -2,6 +2,7 @@ import Fastify from 'fastify';
import cors from '@fastify/cors'; import cors from '@fastify/cors';
import cookie from '@fastify/cookie'; import cookie from '@fastify/cookie';
import rateLimit from '@fastify/rate-limit'; import rateLimit from '@fastify/rate-limit';
import path from 'path';
import { config } from './config/env'; import { config } from './config/env';
import { securityHeaders } from './middleware/security'; import { securityHeaders } from './middleware/security';
@@ -129,6 +130,23 @@ async function start() {
}); });
} }
// --- Frontend: static file serving (production) ---
if (config.isProduction) {
const fastifyStatic = (await import('@fastify/static')).default;
await app.register(fastifyStatic, {
root: path.join(__dirname, '..', 'dist-client'),
prefix: '/',
wildcard: false,
});
app.setNotFoundHandler((request, reply) => {
if (request.url.startsWith('/api/')) {
return reply.status(404).send({ success: false, error: 'Not found' });
}
return reply.sendFile('index.html');
});
}
// --- Start --- // --- Start ---
const port = config.isProduction ? config.port : 3000; const port = config.isProduction ? config.port : 3000;
try { try {
@@ -138,6 +156,23 @@ async function start() {
app.log.error(err); app.log.error(err);
process.exit(1); process.exit(1);
} }
const shutdown = async (signal: string) => {
app.log.info(`${signal} received, shutting down gracefully...`);
try {
await app.close();
const { default: prisma } = await import('./config/database');
await prisma.$disconnect();
app.log.info('Server shut down successfully');
process.exit(0);
} catch (err) {
app.log.error(err, 'Error during shutdown');
process.exit(1);
}
};
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
} }
start(); start();