stock-bot/apps/data-services/data-catalog/src/controllers/HealthController.ts

172 lines
4.7 KiB
TypeScript

import { Hono } from 'hono';
export class HealthController {
private app: Hono;
constructor() {
this.app = new Hono();
this.setupRoutes();
}
private setupRoutes() {
// Basic health check
this.app.get('/', async (c) => {
return c.json({
service: 'data-catalog',
status: 'healthy',
timestamp: new Date().toISOString(),
version: process.env.SERVICE_VERSION || '1.0.0'
});
});
// Detailed health check
this.app.get('/detailed', async (c) => {
try {
const healthStatus = {
service: 'data-catalog',
status: 'healthy',
timestamp: new Date().toISOString(),
version: process.env.SERVICE_VERSION || '1.0.0',
uptime: process.uptime(),
memory: process.memoryUsage(),
dependencies: {
database: await this.checkDatabase(),
search: await this.checkSearchService(),
eventBus: await this.checkEventBus()
}
};
// Determine overall status based on dependencies
const hasUnhealthyDependencies = Object.values(healthStatus.dependencies)
.some(dep => dep.status !== 'healthy');
if (hasUnhealthyDependencies) {
healthStatus.status = 'degraded';
}
const statusCode = healthStatus.status === 'healthy' ? 200 : 503;
return c.json(healthStatus, statusCode);
} catch (error) {
console.error('Health check error:', error);
return c.json({
service: 'data-catalog',
status: 'unhealthy',
timestamp: new Date().toISOString(),
error: error instanceof Error ? error.message : 'Unknown error'
}, 503);
}
});
// Readiness check
this.app.get('/ready', async (c) => {
try {
// Check if service is ready to accept requests
const readyChecks = await Promise.all([
this.checkDatabase(),
this.checkSearchService()
]);
const isReady = readyChecks.every(check => check.status === 'healthy');
if (isReady) {
return c.json({
service: 'data-catalog',
ready: true,
timestamp: new Date().toISOString()
});
} else {
return c.json({
service: 'data-catalog',
ready: false,
timestamp: new Date().toISOString(),
checks: readyChecks
}, 503);
}
} catch (error) {
console.error('Readiness check error:', error);
return c.json({
service: 'data-catalog',
ready: false,
timestamp: new Date().toISOString(),
error: error instanceof Error ? error.message : 'Unknown error'
}, 503);
}
});
// Liveness check
this.app.get('/live', async (c) => {
return c.json({
service: 'data-catalog',
alive: true,
timestamp: new Date().toISOString()
});
});
}
private async checkDatabase(): Promise<{ name: string; status: string; responseTime?: number }> {
const start = Date.now();
try {
// Simulate database check
// In real implementation, this would ping the actual database
await new Promise(resolve => setTimeout(resolve, 10));
return {
name: 'database',
status: 'healthy',
responseTime: Date.now() - start
};
} catch (error) {
return {
name: 'database',
status: 'unhealthy',
responseTime: Date.now() - start
};
}
}
private async checkSearchService(): Promise<{ name: string; status: string; responseTime?: number }> {
const start = Date.now();
try {
// Simulate search service check
// In real implementation, this would check search index health
await new Promise(resolve => setTimeout(resolve, 5));
return {
name: 'search',
status: 'healthy',
responseTime: Date.now() - start
};
} catch (error) {
return {
name: 'search',
status: 'unhealthy',
responseTime: Date.now() - start
};
}
}
private async checkEventBus(): Promise<{ name: string; status: string; responseTime?: number }> {
const start = Date.now();
try {
// Simulate event bus check
// In real implementation, this would check message broker connectivity
await new Promise(resolve => setTimeout(resolve, 3));
return {
name: 'eventBus',
status: 'healthy',
responseTime: Date.now() - start
};
} catch (error) {
return {
name: 'eventBus',
status: 'unhealthy',
responseTime: Date.now() - start
};
}
}
public getApp(): Hono {
return this.app;
}
}