-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.ts
More file actions
111 lines (89 loc) · 3.03 KB
/
server.ts
File metadata and controls
111 lines (89 loc) · 3.03 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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import 'dotenv/config';
import helmet from 'helmet';
import express from 'express';
import type { Request, Response } from 'express';
import authRouter from './auth/authRouter.js';
import eateryRouter from './eateries/eateryRouter.js';
import financialRouter from './financials/financialsRouter.js';
import itemRouter from './items/itemRouter.js';
import { requireAuth } from './middleware/authentication.js';
import { globalErrorHandler } from './middleware/errorHandler.js';
import { requestLogger } from './middleware/logger.js';
import { ipRateLimiter } from './middleware/rateLimit.js';
import { prisma } from './prisma.js';
import userRouter from './users/userRouter.js';
import { cacheRouter, refreshCacheFromDB } from './utils/cache.js';
import { versionRouter } from './utils/version.js';
const app = express();
// Trust proxy - necessary when behind a reverse proxy (nginx)
app.set('trust proxy', 1);
app.use(requestLogger);
app.use(helmet());
app.use(express.json({ limit: '2mb' }));
app.use(ipRateLimiter);
const router = express.Router();
// Health check endpoint
router.get('/health', async (_: Request, res: Response) => {
const healthCheck = {
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
environment: process.env.NODE_ENV || 'development',
database: 'unknown',
};
try {
// Check database connection
await prisma.$queryRaw`SELECT 1`;
healthCheck.database = 'connected';
res.status(200).json(healthCheck);
} catch {
healthCheck.status = 'unhealthy';
healthCheck.database = 'disconnected';
res.status(503).json(healthCheck);
}
});
// Public routes
router.use('/auth', authRouter);
router.use('/internal/cache', cacheRouter);
router.use('/version', versionRouter);
router.use('/eateries', eateryRouter);
router.use('/items', itemRouter);
// Protected routes
router.use(requireAuth);
router.use('/users', userRouter);
router.use('/financials', financialRouter);
app.use(router);
app.use(globalErrorHandler);
const port = process.env.PORT || '8000';
const server = app.listen(port, async () => {
console.log(`Express app listening at http://localhost:${port}`);
console.log(`Environment: ${process.env.NODE_ENV || 'development'}`);
// Verify database connection on startup
try {
await prisma.$connect();
console.log('Database connected successfully');
} catch (error) {
console.error('Failed to connect to database:', error);
process.exit(1);
}
// Initial cache refresh
await refreshCacheFromDB();
});
// Graceful shutdown
const gracefulShutdown = async () => {
console.log('Shutting down gracefully...');
server.close(async () => {
console.log('HTTP server closed');
// Disconnect from database
await prisma.$disconnect();
console.log('Database disconnected');
process.exit(0);
});
// Force shutdown after 10 seconds
setTimeout(() => {
console.error('Forcing shutdown after timeout');
process.exit(1);
}, 10000);
};
process.on('SIGTERM', gracefulShutdown);
process.on('SIGINT', gracefulShutdown);