feat: enhance health check endpoints with Socket.IO monitoring
- Enhanced /api/health endpoint
- Added Socket.IO status monitoring (engine status, client count, active sockets)
- Added memory usage metrics (heap used, heap total, RSS)
- Returns 503 (degraded) if either CouchDB or Socket.IO is down
- Restructured response with nested 'services' object for better clarity
- Added dedicated /api/health/socketio endpoint
- Provides detailed Socket.IO connection information
- Shows connected clients and active sockets count
- Lists active rooms (event_ and post_ rooms) with member counts
- Useful for debugging real-time connection issues
Benefits:
- Better observability for Kubernetes health probes
- Can monitor Socket.IO connection health separately from database
- Helps diagnose real-time feature issues
- Memory metrics useful for detecting leaks on resource-constrained Raspberry Pi nodes
Response Format:
GET /api/health
{
"status": "healthy",
"timestamp": "...",
"uptime": 123.45,
"services": {
"couchdb": "connected",
"socketIO": {
"status": "running",
"connectedClients": 5,
"activeSockets": 5
}
},
"memory": { ... }
}
GET /api/health/socketio
{
"status": "running",
"connectedClients": 5,
"activeSockets": 5,
"rooms": [
{ "name": "event_123", "members": 3 },
{ "name": "post_456", "members": 2 }
]
}
🤖 Generated with AI Assistant
Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
This commit is contained in:
@@ -147,23 +147,82 @@ app.get("/api/health", async (req, res) => {
|
||||
try {
|
||||
const couchdbStatus = await couchdbService.checkConnection();
|
||||
|
||||
res.status(200).json({
|
||||
status: "healthy",
|
||||
// Check Socket.IO status
|
||||
const socketIOStatus = {
|
||||
engine: io.engine ? "running" : "stopped",
|
||||
connectedClients: io.engine ? io.engine.clientsCount : 0,
|
||||
// Get number of connected sockets
|
||||
sockets: io.sockets ? io.sockets.sockets.size : 0
|
||||
};
|
||||
|
||||
const isHealthy = couchdbStatus && io.engine;
|
||||
|
||||
res.status(isHealthy ? 200 : 503).json({
|
||||
status: isHealthy ? "healthy" : "degraded",
|
||||
timestamp: new Date().toISOString(),
|
||||
uptime: process.uptime(),
|
||||
couchdb: couchdbStatus ? "connected" : "disconnected",
|
||||
services: {
|
||||
couchdb: couchdbStatus ? "connected" : "disconnected",
|
||||
socketIO: {
|
||||
status: socketIOStatus.engine,
|
||||
connectedClients: socketIOStatus.connectedClients,
|
||||
activeSockets: socketIOStatus.sockets
|
||||
}
|
||||
},
|
||||
memory: {
|
||||
heapUsed: Math.round(process.memoryUsage().heapUsed / 1024 / 1024) + " MB",
|
||||
heapTotal: Math.round(process.memoryUsage().heapTotal / 1024 / 1024) + " MB",
|
||||
rss: Math.round(process.memoryUsage().rss / 1024 / 1024) + " MB"
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(503).json({
|
||||
status: "unhealthy",
|
||||
timestamp: new Date().toISOString(),
|
||||
uptime: process.uptime(),
|
||||
couchdb: "disconnected",
|
||||
services: {
|
||||
couchdb: "disconnected",
|
||||
socketIO: "unknown"
|
||||
},
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Detailed Socket.IO health check endpoint
|
||||
app.get("/api/health/socketio", (req, res) => {
|
||||
try {
|
||||
const socketIOInfo = {
|
||||
status: io.engine ? "running" : "stopped",
|
||||
connectedClients: io.engine ? io.engine.clientsCount : 0,
|
||||
activeSockets: io.sockets ? io.sockets.sockets.size : 0,
|
||||
rooms: [],
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
// Get list of active rooms (excluding auto-generated socket ID rooms)
|
||||
if (io.sockets && io.sockets.adapter && io.sockets.adapter.rooms) {
|
||||
const rooms = Array.from(io.sockets.adapter.rooms.keys()).filter(room => {
|
||||
// Filter out socket ID rooms (they start with socket ID pattern)
|
||||
return room.startsWith('event_') || room.startsWith('post_');
|
||||
});
|
||||
|
||||
socketIOInfo.rooms = rooms.map(room => {
|
||||
const roomSize = io.sockets.adapter.rooms.get(room)?.size || 0;
|
||||
return { name: room, members: roomSize };
|
||||
});
|
||||
}
|
||||
|
||||
res.status(200).json(socketIOInfo);
|
||||
} catch (error) {
|
||||
res.status(500).json({
|
||||
status: "error",
|
||||
error: error.message,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Routes
|
||||
app.use("/api/auth", authRoutes);
|
||||
app.use("/api/streets", streetRoutes);
|
||||
|
||||
Reference in New Issue
Block a user