Spaces:
Paused
Paused
| import { Router } from 'express'; | |
| import { neo4jService } from '../database/Neo4jService'; | |
| import { checkPrismaConnection, prisma } from '../database/prisma'; | |
| const router = Router(); | |
| /** | |
| * Overall system health check | |
| */ | |
| router.get('/health', async (req, res) => { | |
| const health = { | |
| status: 'healthy', | |
| timestamp: new Date().toISOString(), | |
| services: { | |
| database: 'unknown', | |
| neo4j: 'unknown', | |
| redis: 'unknown', | |
| }, | |
| uptime: process.uptime(), | |
| memory: process.memoryUsage(), | |
| }; | |
| try { | |
| // Check Prisma/PostgreSQL | |
| const prismaHealthy = await checkPrismaConnection(); | |
| health.services.database = prismaHealthy ? 'healthy' : 'unhealthy'; | |
| if (!prismaHealthy) health.status = 'degraded'; | |
| } catch { | |
| health.services.database = 'unhealthy'; | |
| health.status = 'degraded'; | |
| } | |
| try { | |
| // Check Neo4j | |
| await neo4jService.connect(); | |
| const neo4jHealthy = await neo4jService.healthCheck(); | |
| health.services.neo4j = neo4jHealthy ? 'healthy' : 'unhealthy'; | |
| await neo4jService.disconnect(); | |
| if (!neo4jHealthy) { | |
| health.status = 'degraded'; | |
| } | |
| } catch (error) { | |
| health.services.neo4j = 'unhealthy'; | |
| health.status = 'degraded'; | |
| } | |
| // Check Redis | |
| if (process.env.REDIS_URL) { | |
| // Redis URL is configured but ioredis client is not yet installed | |
| // Once ioredis is installed, this can be updated to perform actual health check | |
| health.services.redis = 'configured_but_client_unavailable'; | |
| } else { | |
| health.services.redis = 'not_configured'; | |
| } | |
| const statusCode = health.status === 'healthy' ? 200 : 503; | |
| res.status(statusCode).json(health); | |
| }); | |
| /** | |
| * Database-specific health check | |
| */ | |
| router.get('/health/database', async (req, res) => { | |
| try { | |
| const prismaHealthy = await checkPrismaConnection(); | |
| if (!prismaHealthy) { | |
| return res.status(503).json({ | |
| status: 'unhealthy', | |
| error: 'Prisma unreachable', | |
| }); | |
| } | |
| const result = await prisma.$queryRaw`SELECT 1 as test`; | |
| res.json({ | |
| status: 'healthy', | |
| type: 'PostgreSQL (Prisma)', | |
| tables: 'n/a', | |
| test: (result as any[])[0]?.test === 1, | |
| }); | |
| } catch (error) { | |
| res.status(503).json({ | |
| status: 'unhealthy', | |
| error: String(error), | |
| }); | |
| } | |
| }); | |
| /** | |
| * Neo4j-specific health check | |
| */ | |
| router.get('/health/neo4j', async (req, res) => { | |
| try { | |
| await neo4jService.connect(); | |
| const healthy = await neo4jService.healthCheck(); | |
| if (healthy) { | |
| const stats = await neo4jService.runQuery('MATCH (n) RETURN count(n) as nodeCount'); | |
| await neo4jService.disconnect(); | |
| res.json({ | |
| status: 'healthy', | |
| connected: true, | |
| nodeCount: stats[0]?.nodeCount || 0, | |
| }); | |
| } else { | |
| throw new Error('Health check failed'); | |
| } | |
| } catch (error) { | |
| res.status(503).json({ | |
| status: 'unhealthy', | |
| connected: false, | |
| error: String(error), | |
| }); | |
| } | |
| }); | |
| /** | |
| * Readiness check (for Kubernetes) | |
| */ | |
| router.get('/ready', async (req, res) => { | |
| try { | |
| // Use Prisma connection check instead of SQLite | |
| const prismaHealthy = await checkPrismaConnection(); | |
| if (!prismaHealthy) { | |
| throw new Error('Database not ready'); | |
| } | |
| res.json({ | |
| status: 'ready', | |
| timestamp: new Date().toISOString(), | |
| }); | |
| } catch (error) { | |
| res.status(503).json({ | |
| status: 'not_ready', | |
| error: String(error), | |
| }); | |
| } | |
| }); | |
| /** | |
| * Liveness check (for Kubernetes) | |
| */ | |
| router.get('/live', (req, res) => { | |
| res.json({ | |
| status: 'alive', | |
| timestamp: new Date().toISOString(), | |
| uptime: process.uptime(), | |
| }); | |
| }); | |
| export default router; | |