@ai-capabilities-suite/mcp-debugger-core
Version:
Core debugging engine for Node.js and TypeScript applications. Provides Inspector Protocol integration, breakpoint management, variable inspection, execution control, profiling, hang detection, and source map support.
226 lines • 7.02 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.HealthChecker = exports.HealthStatus = void 0;
exports.createSimpleDependencyChecker = createSimpleDependencyChecker;
/**
* Health status enumeration
*/
var HealthStatus;
(function (HealthStatus) {
HealthStatus["HEALTHY"] = "healthy";
HealthStatus["UNHEALTHY"] = "unhealthy";
HealthStatus["DEGRADED"] = "degraded";
})(HealthStatus || (exports.HealthStatus = HealthStatus = {}));
/**
* Health checker for production readiness
* Provides health, readiness, and liveness endpoints
*/
class HealthChecker {
constructor() {
this.dependencyCheckers = new Map();
this.startTime = Date.now();
}
/**
* Register a dependency health checker
*/
registerDependencyChecker(name, checker) {
this.dependencyCheckers.set(name, checker);
}
/**
* Unregister a dependency health checker
*/
unregisterDependencyChecker(name) {
this.dependencyCheckers.delete(name);
}
/**
* Get uptime in milliseconds
*/
getUptime() {
return Date.now() - this.startTime;
}
/**
* Check health of a single dependency
*/
async checkDependency(name, checker) {
const startTime = Date.now();
let timeoutId = null;
try {
const result = await Promise.race([
checker(),
new Promise((_, reject) => {
timeoutId = setTimeout(() => reject(new Error('Health check timeout')), 5000);
}),
]);
if (timeoutId)
clearTimeout(timeoutId);
return {
...result,
latency: Date.now() - startTime,
};
}
catch (error) {
if (timeoutId)
clearTimeout(timeoutId);
return {
name,
status: HealthStatus.UNHEALTHY,
message: error instanceof Error ? error.message : String(error),
latency: Date.now() - startTime,
};
}
}
/**
* Perform health check
* Checks all registered dependencies and returns overall health status
*/
async checkHealth() {
const dependencies = [];
// Check all dependencies
for (const [name, checker] of this.dependencyCheckers.entries()) {
const health = await this.checkDependency(name, checker);
dependencies.push(health);
}
// Determine overall status
let overallStatus = HealthStatus.HEALTHY;
const unhealthyCount = dependencies.filter((d) => d.status === HealthStatus.UNHEALTHY).length;
const degradedCount = dependencies.filter((d) => d.status === HealthStatus.DEGRADED).length;
if (unhealthyCount > 0) {
overallStatus = HealthStatus.UNHEALTHY;
}
else if (degradedCount > 0) {
overallStatus = HealthStatus.DEGRADED;
}
const result = {
status: overallStatus,
timestamp: new Date().toISOString(),
uptime: this.getUptime(),
dependencies,
};
this.lastHealthCheck = result;
return result;
}
/**
* Get last health check result (cached)
*/
getLastHealthCheck() {
return this.lastHealthCheck;
}
/**
* Perform readiness check
* Checks if the service is ready to accept requests
*/
async checkReadiness() {
const checks = [];
// Check if dependencies are healthy
for (const [name, checker] of this.dependencyCheckers.entries()) {
const health = await this.checkDependency(name, checker);
checks.push({
name,
ready: health.status !== HealthStatus.UNHEALTHY,
message: health.message,
});
}
// Service is ready if all dependencies are not unhealthy
const ready = checks.every((check) => check.ready);
return {
ready,
timestamp: new Date().toISOString(),
checks,
};
}
/**
* Perform liveness check
* Checks if the service is alive and responsive
*/
async checkLiveness() {
// Basic liveness check - if we can execute this, we're alive
// In a real implementation, you might check for deadlocks, etc.
try {
// Simple check: can we get the current time?
const now = Date.now();
return {
alive: true,
timestamp: new Date(now).toISOString(),
};
}
catch (error) {
return {
alive: false,
timestamp: new Date().toISOString(),
message: error instanceof Error ? error.message : String(error),
};
}
}
/**
* Start periodic health checks
*/
startPeriodicHealthChecks(intervalMs = 30000) {
if (this.healthCheckInterval) {
clearInterval(this.healthCheckInterval);
}
this.healthCheckInterval = setInterval(async () => {
await this.checkHealth();
}, intervalMs);
}
/**
* Stop periodic health checks
*/
stopPeriodicHealthChecks() {
if (this.healthCheckInterval) {
clearInterval(this.healthCheckInterval);
this.healthCheckInterval = undefined;
}
}
/**
* Get health endpoint data (for HTTP endpoint)
*/
async getHealthEndpointData() {
const health = await this.checkHealth();
return JSON.stringify(health, null, 2);
}
/**
* Get readiness endpoint data (for HTTP endpoint)
*/
async getReadinessEndpointData() {
const readiness = await this.checkReadiness();
return JSON.stringify(readiness, null, 2);
}
/**
* Get liveness endpoint data (for HTTP endpoint)
*/
async getLivenessEndpointData() {
const liveness = await this.checkLiveness();
return JSON.stringify(liveness, null, 2);
}
/**
* Cleanup resources
*/
cleanup() {
this.stopPeriodicHealthChecks();
this.dependencyCheckers.clear();
}
}
exports.HealthChecker = HealthChecker;
/**
* Create a simple dependency checker for testing
*/
function createSimpleDependencyChecker(name, checkFn) {
return async () => {
try {
const isHealthy = await checkFn();
return {
name,
status: isHealthy ? HealthStatus.HEALTHY : HealthStatus.UNHEALTHY,
message: isHealthy ? 'OK' : 'Check failed',
};
}
catch (error) {
return {
name,
status: HealthStatus.UNHEALTHY,
message: error instanceof Error ? error.message : String(error),
};
}
};
}
//# sourceMappingURL=health-checker.js.map