Skip to main content
Glama
health.ts11.6 kB
/** * Health Routes * * REST API endpoints for health monitoring and system status. * Provides full health check, readiness probe, and liveness probe endpoints. * * Requirements: 13.1, 13.2, 13.3 */ import { Router, type Request, type Response } from "express"; import { healthChecker } from "../../monitoring/health-checker.js"; import type { CognitiveCore } from "../cognitive-core.js"; import { asyncHandler } from "../middleware/error-handler.js"; import { getPerformanceStats } from "../middleware/performance.js"; import { getResponseCacheMetrics } from "../middleware/response-cache.js"; import { buildSuccessResponse } from "../types/api-response.js"; /** * Component health status * Requirements: 13.1 */ interface ComponentHealth { /** Health status */ status: "healthy" | "degraded" | "unhealthy"; /** Response latency in milliseconds */ latency?: number; /** Last successful check timestamp */ lastCheck: string; /** Error message if unhealthy */ message?: string; } /** * Performance metrics for health response * Requirements: 13.1, 17.1 */ interface HealthMetrics { /** System uptime in seconds */ uptime: number; /** Total request count (from metrics if available) */ requestCount: number; /** Average response time in milliseconds */ avgResponseTime: number; /** p95 response time in milliseconds */ p95ResponseTime: number; /** Memory usage in bytes */ memoryUsage: number; /** Response cache statistics */ cache: { hits: number; misses: number; hitRate: number; size: number; }; } /** * Full health response type * Requirements: 13.1 */ interface HealthResponse { /** Overall system status */ status: "healthy" | "degraded" | "unhealthy"; /** Individual component health */ components: { database: ComponentHealth; embeddingEngine: ComponentHealth; reasoning: ComponentHealth; memory: ComponentHealth; }; /** System performance metrics */ metrics: HealthMetrics; } /** * Readiness response type * Requirements: 13.2 */ interface ReadinessResponse { /** Whether system is ready to accept requests */ ready: boolean; /** Reason if not ready */ reason?: string; } /** * Liveness response type * Requirements: 13.3 */ interface LivenessResponse { /** Whether system is alive/running */ alive: boolean; /** System uptime in seconds */ uptime: number; } /** * Helper to extract request ID from request */ function getRequestId(req: Request): string | undefined { return (req as Request & { requestId?: string }).requestId; } /** * Get system uptime in seconds */ function getUptimeSeconds(): number { return Math.floor(process.uptime()); } /** * Get memory usage in bytes */ function getMemoryUsage(): number { return process.memoryUsage().heapUsed; } /** * Create a component health object from health check result */ function createComponentHealth( status: "healthy" | "degraded" | "unhealthy", latency?: number, message?: string ): ComponentHealth { return { status, latency, lastCheck: new Date().toISOString(), message, }; } /** * Check database health */ async function checkDatabaseHealth(cognitiveCore: CognitiveCore): Promise<ComponentHealth> { const startTime = Date.now(); try { // Try to access memory repository which uses database // If it's available and can be accessed, database is healthy if (cognitiveCore.memoryRepository) { // The memory repository existing indicates database connection is available const latency = Date.now() - startTime; return createComponentHealth("healthy", latency); } return createComponentHealth( "unhealthy", Date.now() - startTime, "Memory repository not available" ); } catch (error) { const latency = Date.now() - startTime; const message = error instanceof Error ? error.message : "Database check failed"; return createComponentHealth("unhealthy", latency, message); } } /** * Check embedding engine health */ async function checkEmbeddingEngineHealth(_cognitiveCore: CognitiveCore): Promise<ComponentHealth> { const startTime = Date.now(); try { // Check if embedding-related components are available via health checker const embeddingCheck = healthChecker.getLastResult("embedding"); if (embeddingCheck) { return createComponentHealth( embeddingCheck.status, embeddingCheck.responseTimeMs, embeddingCheck.error ); } // If no specific check registered, assume healthy if we got this far const latency = Date.now() - startTime; return createComponentHealth("healthy", latency); } catch (error) { const latency = Date.now() - startTime; const message = error instanceof Error ? error.message : "Embedding engine check failed"; return createComponentHealth("unhealthy", latency, message); } } /** * Check reasoning system health */ async function checkReasoningHealth(cognitiveCore: CognitiveCore): Promise<ComponentHealth> { const startTime = Date.now(); try { // Check if reasoning orchestrator is available if (cognitiveCore.reasoningOrchestrator) { const latency = Date.now() - startTime; return createComponentHealth("healthy", latency); } return createComponentHealth( "unhealthy", Date.now() - startTime, "Reasoning orchestrator not available" ); } catch (error) { const latency = Date.now() - startTime; const message = error instanceof Error ? error.message : "Reasoning check failed"; return createComponentHealth("unhealthy", latency, message); } } /** * Check memory system health */ async function checkMemoryHealth(cognitiveCore: CognitiveCore): Promise<ComponentHealth> { const startTime = Date.now(); try { // Check if memory repository is available if (cognitiveCore.memoryRepository) { const latency = Date.now() - startTime; return createComponentHealth("healthy", latency); } return createComponentHealth( "unhealthy", Date.now() - startTime, "Memory repository not available" ); } catch (error) { const latency = Date.now() - startTime; const message = error instanceof Error ? error.message : "Memory check failed"; return createComponentHealth("unhealthy", latency, message); } } /** * Determine overall status from component statuses */ function determineOverallStatus( components: HealthResponse["components"] ): "healthy" | "degraded" | "unhealthy" { const statuses = Object.values(components).map((c) => c.status); // If any component is unhealthy, overall is unhealthy if (statuses.some((s) => s === "unhealthy")) { return "unhealthy"; } // If any component is degraded, overall is degraded if (statuses.some((s) => s === "degraded")) { return "degraded"; } return "healthy"; } /** * Handler for GET /api/v1/health * Requirements: 13.1 * * Returns overall health status, component health (database, embedding engine, * reasoning, memory), and performance metrics. */ function createHealthHandler( cognitiveCore: CognitiveCore ): (req: Request, res: Response, next: import("express").NextFunction) => void { return asyncHandler(async (req: Request, res: Response): Promise<void> => { const startTime = Date.now(); const requestId = getRequestId(req); // Check all components in parallel const [database, embeddingEngine, reasoning, memory] = await Promise.all([ checkDatabaseHealth(cognitiveCore), checkEmbeddingEngineHealth(cognitiveCore), checkReasoningHealth(cognitiveCore), checkMemoryHealth(cognitiveCore), ]); const components = { database, embeddingEngine, reasoning, memory, }; const status = determineOverallStatus(components); // Get performance stats from middleware const perfStats = getPerformanceStats(); const cacheMetrics = getResponseCacheMetrics(); const metrics: HealthMetrics = { uptime: getUptimeSeconds(), requestCount: perfStats.totalRequests, avgResponseTime: perfStats.avgDurationMs, p95ResponseTime: perfStats.p95DurationMs, memoryUsage: getMemoryUsage(), cache: cacheMetrics, }; const responseData: HealthResponse = { status, components, metrics, }; // Return appropriate HTTP status based on health const httpStatus = status === "healthy" ? 200 : status === "degraded" ? 200 : 503; res.status(httpStatus).json(buildSuccessResponse(responseData, { requestId, startTime })); }); } /** * Handler for GET /api/v1/health/ready * Requirements: 13.2 * * Returns readiness status indicating if the system can accept requests. * Used by Kubernetes/container orchestrators for readiness probes. */ function createReadinessHandler( cognitiveCore: CognitiveCore ): (req: Request, res: Response, next: import("express").NextFunction) => void { return asyncHandler(async (req: Request, res: Response): Promise<void> => { const startTime = Date.now(); const requestId = getRequestId(req); // Check critical components for readiness const [database, memory] = await Promise.all([ checkDatabaseHealth(cognitiveCore), checkMemoryHealth(cognitiveCore), ]); // System is ready if critical components are not unhealthy const criticalUnhealthy = database.status === "unhealthy" || memory.status === "unhealthy"; const ready = !criticalUnhealthy; let reason: string | undefined; if (!ready) { const unhealthyComponents: string[] = []; if (database.status === "unhealthy") { unhealthyComponents.push(`database: ${database.message ?? "unhealthy"}`); } if (memory.status === "unhealthy") { unhealthyComponents.push(`memory: ${memory.message ?? "unhealthy"}`); } reason = `Critical components unhealthy: ${unhealthyComponents.join(", ")}`; } const responseData: ReadinessResponse = { ready, reason, }; const httpStatus = ready ? 200 : 503; res.status(httpStatus).json(buildSuccessResponse(responseData, { requestId, startTime })); }); } /** * Handler for GET /api/v1/health/live * Requirements: 13.3 * * Returns liveness status indicating if the system is running. * Used by Kubernetes/container orchestrators for liveness probes. */ function createLivenessHandler(): ( req: Request, res: Response, next: import("express").NextFunction ) => void { return asyncHandler(async (req: Request, res: Response): Promise<void> => { const startTime = Date.now(); const requestId = getRequestId(req); // Liveness check is simple - if we can respond, we're alive const responseData: LivenessResponse = { alive: true, uptime: getUptimeSeconds(), }; res.status(200).json(buildSuccessResponse(responseData, { requestId, startTime })); }); } /** * Create health routes * Requirements: 13.1, 13.2, 13.3 * * @param cognitiveCore - Shared cognitive core instance * @returns Express router with health endpoints */ export function createHealthRoutes(cognitiveCore: CognitiveCore): Router { const router = Router(); // GET /api/v1/health - Full health check // Requirements: 13.1 router.get("/", createHealthHandler(cognitiveCore)); // GET /api/v1/health/ready - Readiness probe // Requirements: 13.2 router.get("/ready", createReadinessHandler(cognitiveCore)); // GET /api/v1/health/live - Liveness probe // Requirements: 13.3 router.get("/live", createLivenessHandler()); return router; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/keyurgolani/ThoughtMcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server