import { Controller, Get } from '@nestjs/common';
import { LogseqClient } from '../logseq/logseq.client';
interface HealthCheckResult {
status: 'ok' | 'error';
timestamp: string;
version: string;
uptime: number;
checks: {
logseq: {
status: 'up' | 'down';
graph?: string;
error?: string;
};
};
}
/**
* Health Check 컨트롤러
*
* 원격 MCP 서버의 상태를 확인하기 위한 엔드포인트 제공
* - GET /health: 전체 상태 확인
* - GET /health/live: 서버 생존 확인 (Kubernetes liveness probe)
* - GET /health/ready: 서비스 준비 상태 확인 (Kubernetes readiness probe)
*/
@Controller('health')
export class HealthController {
private readonly startTime = Date.now();
constructor(private readonly logseqClient: LogseqClient) {}
/**
* 전체 Health Check
*/
@Get()
async check(): Promise<HealthCheckResult> {
const logseqCheck = await this.checkLogseq();
return {
status: logseqCheck.status === 'up' ? 'ok' : 'error',
timestamp: new Date().toISOString(),
version: process.env.npm_package_version || '0.0.1',
uptime: Math.floor((Date.now() - this.startTime) / 1000),
checks: {
logseq: logseqCheck,
},
};
}
/**
* Liveness Probe - 서버가 살아있는지 확인
*/
@Get('live')
live(): { status: 'ok' } {
return { status: 'ok' };
}
/**
* Readiness Probe - 서비스가 요청을 받을 준비가 되었는지 확인
*/
@Get('ready')
async ready(): Promise<{ status: 'ok' | 'error'; message?: string }> {
const logseqCheck = await this.checkLogseq();
if (logseqCheck.status === 'down') {
return {
status: 'error',
message: `Logseq not ready: ${logseqCheck.error}`,
};
}
return { status: 'ok' };
}
/**
* Logseq 연결 상태 확인
*/
private async checkLogseq(): Promise<{
status: 'up' | 'down';
graph?: string;
error?: string;
}> {
try {
const graph = await this.logseqClient.getCurrentGraph();
if (graph) {
return {
status: 'up',
graph: graph.name,
};
}
return {
status: 'down',
error: 'No graph opened in Logseq',
};
} catch (error) {
return {
status: 'down',
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
}