Repository navigation
Expand file tree
/
Copy pathserver.ts
More file actions
73 lines (61 loc) · 2.66 KB
/
Copy pathserver.ts
File metadata and controls
73 lines (61 loc) · 2.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// IMPORTANT: `node-environment-baseline` MUST be the first import so that
// `globalThis.AsyncLocalStorage` is installed before any Next.js module is
// evaluated. Re-ordering these imports will break the production boot path
// (see lib/runtime/node-environment-baseline.ts for rationale).
import './lib/runtime/node-environment-baseline';
import { logger } from './lib/logger';
import { bootstrapEnvironment } from './lib/runtime/env-bootstrap';
import { runAdminBootstrapOrExit } from './lib/runtime/admin-bootstrap';
import { createHttpServer } from './lib/server/http-server';
import { createSocketServer } from './lib/server/socket-server';
import { startWorkerServer, stopWorkerServer } from './lib/server/worker-server';
bootstrapEnvironment();
let isShuttingDown = false;
const GRACEFUL_SHUTDOWN_TIMEOUT = Number(process.env.GRACEFUL_SHUTDOWN_TIMEOUT_MS) || 30000;
const start = async () => {
await runAdminBootstrapOrExit();
const runtimeMode = (process.env.RUNTIME_MODE || 'all').toLowerCase();
const runApi = runtimeMode === 'all' || runtimeMode === 'api';
const runWorker = runtimeMode === 'all' || runtimeMode === 'worker';
const http = runApi ? await createHttpServer(() => isShuttingDown) : null;
const io = http ? await createSocketServer(http.server, http.runtime) : null;
if (runWorker) {
await startWorkerServer();
}
if (http) {
http.server.listen(http.runtime.port, http.runtime.hostname, () => {
logger.info(`> Ready on http://${http.runtime.hostname}:${http.runtime.port}`);
});
}
const gracefulShutdown = async (signal: string) => {
if (isShuttingDown) return;
isShuttingDown = true;
const forceExitTimer = setTimeout(() => process.exit(1), GRACEFUL_SHUTDOWN_TIMEOUT);
try {
if (http) {
await new Promise<void>((resolve, reject) => {
http.server.close((err) => (err ? reject(err) : resolve()));
});
}
if (io) {
await new Promise<void>((resolve) => io.close(() => resolve()));
}
if (runWorker) {
await stopWorkerServer();
}
clearTimeout(forceExitTimer);
logger.info('Graceful shutdown complete', { signal });
process.exit(0);
} catch (error) {
clearTimeout(forceExitTimer);
logger.error('Graceful shutdown failed', { signal, error: error instanceof Error ? error.message : String(error) });
process.exit(1);
}
};
process.on('SIGTERM', () => void gracefulShutdown('SIGTERM'));
process.on('SIGINT', () => void gracefulShutdown('SIGINT'));
};
start().catch((error) => {
logger.error('Failed to start server', { error: error instanceof Error ? error.message : String(error) });
process.exit(1);
});