feat(admin): add /api/admin/health endpoint for service status checks
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 39s
CI / test-python-backend-compliance (push) Successful in 31s
CI / test-python-document-crawler (push) Successful in 26s
CI / test-python-dsms-gateway (push) Successful in 23s
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 39s
CI / test-python-backend-compliance (push) Successful in 31s
CI / test-python-document-crawler (push) Successful in 26s
CI / test-python-dsms-gateway (push) Successful in 23s
Create server-side health check API that probes actual compliance services (Backend, AI SDK, Ollama, TTS, Embedding, RAG, Qdrant, Valkey, MinIO) from within the Docker network. Replaces the non-existent endpoint that caused all services to show as offline. Also updates ServiceStatus component to list compliance-relevant services instead of lehrer services. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
82
admin-compliance/app/api/admin/health/route.ts
Normal file
82
admin-compliance/app/api/admin/health/route.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
|
||||
interface ServiceCheck {
|
||||
name: string
|
||||
port: number
|
||||
category: 'core' | 'ai' | 'database' | 'storage'
|
||||
url: string
|
||||
expectJson?: boolean
|
||||
}
|
||||
|
||||
const SERVICES: ServiceCheck[] = [
|
||||
// Core Services
|
||||
{ name: 'Backend API', port: 8002, category: 'core', url: 'http://backend-compliance:8002/health' },
|
||||
{ name: 'AI Compliance SDK', port: 8093, category: 'core', url: 'http://ai-compliance-sdk:8090/health' },
|
||||
{ name: 'Consent Service', port: 8081, category: 'core', url: 'http://bp-core-consent-service:8081/health' },
|
||||
{ name: 'TTS Service', port: 8095, category: 'core', url: 'http://compliance-tts-service:8095/health' },
|
||||
// AI / LLM
|
||||
{ name: 'Ollama/LLM', port: 11434, category: 'ai', url: `${process.env.OLLAMA_URL || 'http://host.docker.internal:11434'}/api/tags`, expectJson: true },
|
||||
{ name: 'Embedding Service', port: 8087, category: 'ai', url: 'http://bp-core-embedding-service:8087/health' },
|
||||
{ name: 'RAG Service', port: 8089, category: 'ai', url: 'http://bp-core-rag-service:8089/health' },
|
||||
// Databases
|
||||
{ name: 'Qdrant (Vector DB)', port: 6333, category: 'database', url: 'http://bp-core-qdrant:6333/readyz' },
|
||||
{ name: 'Valkey (Cache)', port: 6379, category: 'database', url: '' }, // TCP only, checked via SDK health
|
||||
{ name: 'MinIO (S3)', port: 9000, category: 'storage', url: 'http://bp-core-minio:9000/minio/health/live' },
|
||||
]
|
||||
|
||||
async function checkService(service: ServiceCheck): Promise<{
|
||||
name: string
|
||||
port: number
|
||||
category: string
|
||||
status: 'online' | 'offline' | 'degraded'
|
||||
responseTime?: number
|
||||
details?: string
|
||||
}> {
|
||||
if (!service.url) {
|
||||
// Can't HTTP-check TCP-only services — mark as degraded with hint
|
||||
return { name: service.name, port: service.port, category: service.category, status: 'degraded', details: 'Kein HTTP-Health-Endpoint' }
|
||||
}
|
||||
|
||||
const start = Date.now()
|
||||
try {
|
||||
const controller = new AbortController()
|
||||
const timeout = setTimeout(() => controller.abort(), 5000)
|
||||
|
||||
const res = await fetch(service.url, { signal: controller.signal, cache: 'no-store' })
|
||||
clearTimeout(timeout)
|
||||
|
||||
const responseTime = Date.now() - start
|
||||
|
||||
if (res.ok) {
|
||||
let details: string | undefined
|
||||
if (service.expectJson) {
|
||||
try {
|
||||
const data = await res.json()
|
||||
if (data.models) {
|
||||
details = `${data.models.length} Modelle`
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
return { name: service.name, port: service.port, category: service.category, status: 'online', responseTime, details }
|
||||
}
|
||||
|
||||
return { name: service.name, port: service.port, category: service.category, status: 'degraded', responseTime, details: `HTTP ${res.status}` }
|
||||
} catch (err) {
|
||||
return {
|
||||
name: service.name,
|
||||
port: service.port,
|
||||
category: service.category,
|
||||
status: 'offline',
|
||||
details: err instanceof Error && err.name === 'AbortError' ? 'Timeout (5s)' : 'Nicht erreichbar',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
const results = await Promise.all(SERVICES.map(checkService))
|
||||
|
||||
return NextResponse.json({
|
||||
services: results,
|
||||
timestamp: new Date().toISOString(),
|
||||
})
|
||||
}
|
||||
@@ -13,16 +13,13 @@ interface ServiceHealth {
|
||||
|
||||
// Initial services list for loading state
|
||||
const INITIAL_SERVICES: Omit<ServiceHealth, 'status' | 'responseTime' | 'details'>[] = [
|
||||
{ name: 'Backend API', port: 8000, category: 'core' },
|
||||
{ name: 'Backend API', port: 8002, category: 'core' },
|
||||
{ name: 'AI Compliance SDK', port: 8093, category: 'core' },
|
||||
{ name: 'Consent Service', port: 8081, category: 'core' },
|
||||
{ name: 'Voice Service', port: 8091, category: 'core' },
|
||||
{ name: 'Klausur Service', port: 8086, category: 'core' },
|
||||
{ name: 'Mail Service (Mailpit)', port: 8025, category: 'core' },
|
||||
{ name: 'Edu Search', port: 8088, category: 'core' },
|
||||
{ name: 'H5P Service', port: 8092, category: 'core' },
|
||||
{ name: 'TTS Service', port: 8095, category: 'core' },
|
||||
{ name: 'Ollama/LLM', port: 11434, category: 'ai' },
|
||||
{ name: 'Embedding Service', port: 8087, category: 'ai' },
|
||||
{ name: 'PostgreSQL', port: 5432, category: 'database' },
|
||||
{ name: 'RAG Service', port: 8089, category: 'ai' },
|
||||
{ name: 'Qdrant (Vector DB)', port: 6333, category: 'database' },
|
||||
{ name: 'Valkey (Cache)', port: 6379, category: 'database' },
|
||||
{ name: 'MinIO (S3)', port: 9000, category: 'storage' },
|
||||
|
||||
Reference in New Issue
Block a user