58 lines
2.2 KiB
TypeScript
58 lines
2.2 KiB
TypeScript
/**
|
|
* Monitoring & Health Check — aggregates health from all services.
|
|
*
|
|
* Standalone script that polls each service's /health endpoint and
|
|
* reports combined status. Can be run as a cron job, GitHub Action,
|
|
* or standalone HTTP endpoint.
|
|
*
|
|
* Usage:
|
|
* npx tsx services/monitoring/health-check.ts # one-shot check
|
|
* npx tsx services/monitoring/health-check.ts --serve # HTTP server on :4004
|
|
*
|
|
* Environment:
|
|
* BACKEND_URL (default: http://localhost:8000)
|
|
* GROWTH_SERVICE_URL (default: http://localhost:4001)
|
|
* BILLING_SERVICE_URL (default: http://localhost:4002)
|
|
* PLATFORM_SERVICE_URL (default: http://localhost:4003)
|
|
* ADMIN_DASHBOARD_URL (default: http://localhost:3001)
|
|
* USER_DASHBOARD_URL (default: http://localhost:3002)
|
|
*/
|
|
|
|
import { DEFAULT_SERVICES, generateHealthReport } from '@bytelyst/monitoring';
|
|
|
|
// ── CLI / HTTP server mode ──
|
|
|
|
const args = process.argv.slice(2);
|
|
|
|
if (args.includes('--serve')) {
|
|
// Run as HTTP server for continuous monitoring
|
|
const { createServer } = await import('http');
|
|
const PORT = Number(process.env.MONITOR_PORT || 4004);
|
|
|
|
const server = createServer(async (_req, res) => {
|
|
const report = await generateHealthReport(DEFAULT_SERVICES);
|
|
res.writeHead(report.overall === 'healthy' ? 200 : 503, { 'Content-Type': 'application/json' });
|
|
res.end(JSON.stringify(report, null, 2));
|
|
});
|
|
|
|
server.listen(PORT, () => {
|
|
console.log(`🩺 Monitoring dashboard running on http://localhost:${PORT}`);
|
|
console.log(` Checking ${DEFAULT_SERVICES.length} services every request`);
|
|
});
|
|
} else {
|
|
// One-shot check
|
|
const report = await generateHealthReport(DEFAULT_SERVICES);
|
|
const icon = { healthy: '✅', degraded: '⚠️', down: '❌' };
|
|
console.log(`\n${icon[report.overall]} Overall: ${report.overall.toUpperCase()}\n`);
|
|
|
|
for (const svc of report.services) {
|
|
const sIcon = { healthy: '✅', unhealthy: '⚠️', unreachable: '❌' };
|
|
console.log(
|
|
` ${sIcon[svc.status]} ${svc.name.padEnd(20)} ${svc.responseTimeMs}ms${svc.error ? ` — ${svc.error}` : ''}`
|
|
);
|
|
}
|
|
|
|
console.log(`\nHealthy: ${report.summary.healthy}/${report.summary.total}`);
|
|
process.exit(report.overall === 'healthy' ? 0 : 1);
|
|
}
|