UNPKG

@layr-labs/hourglass-performer

Version:

TypeScript SDK for building Hourglass AVS performers

248 lines 8.19 kB
"use strict"; // Health and status management for the performer server Object.defineProperty(exports, "__esModule", { value: true }); exports.HealthManager = exports.UptimeHealthProvider = exports.MemoryHealthProvider = void 0; const performer_1 = require("../types/performer"); /** * Built-in health check providers */ class MemoryHealthProvider { constructor(maxMemoryMB = 512) { this.maxMemoryMB = maxMemoryMB; this.name = 'memory'; } async check() { const memUsage = process.memoryUsage(); const usedMB = memUsage.heapUsed / 1024 / 1024; return { healthy: usedMB < this.maxMemoryMB, details: { usedMB: Math.round(usedMB), maxMB: this.maxMemoryMB, heapUsed: memUsage.heapUsed, heapTotal: memUsage.heapTotal, }, error: usedMB >= this.maxMemoryMB ? `Memory usage ${Math.round(usedMB)}MB exceeds limit ${this.maxMemoryMB}MB` : undefined, }; } } exports.MemoryHealthProvider = MemoryHealthProvider; class UptimeHealthProvider { constructor(startTime = Date.now()) { this.startTime = startTime; this.name = 'uptime'; } async check() { const uptime = Date.now() - this.startTime; return { healthy: true, details: { uptimeMs: uptime, uptimeSeconds: Math.round(uptime / 1000), startTime: this.startTime, }, }; } } exports.UptimeHealthProvider = UptimeHealthProvider; /** * Health manager for tracking performer health and status */ class HealthManager { constructor(logger, config = {}) { this.logger = logger; this.currentStatus = performer_1.PerformerStatus.STARTING; this.providers = new Map(); this.failures = 0; this.startTime = Date.now(); this.taskCount = 0; this.errors = []; this.customMetrics = new Map(); this.config = { checkInterval: config.checkInterval ?? 30000, // 30 seconds maxFailures: config.maxFailures ?? 3, timeout: config.timeout ?? 5000, // 5 seconds autoRecover: config.autoRecover ?? true, }; // Add built-in health check providers this.addProvider(new MemoryHealthProvider()); this.addProvider(new UptimeHealthProvider(this.startTime)); } /** * Start the health manager */ start() { this.currentStatus = performer_1.PerformerStatus.READY_FOR_TASK; this.logger.info('Health manager started'); // Start periodic health checks if (this.config.checkInterval > 0) { this.healthCheckInterval = setInterval(() => { this.performHealthCheck().catch(error => { this.logger.error('Health check failed', { error: error.message }); }); }, this.config.checkInterval); } } /** * Stop the health manager */ stop() { this.currentStatus = performer_1.PerformerStatus.STOPPING; if (this.healthCheckInterval) { clearInterval(this.healthCheckInterval); this.healthCheckInterval = undefined; } this.logger.info('Health manager stopped'); } /** * Add a custom health check provider */ addProvider(provider) { this.providers.set(provider.name, provider); this.logger.debug(`Added health check provider: ${provider.name}`); } /** * Remove a health check provider */ removeProvider(name) { this.providers.delete(name); this.logger.debug(`Removed health check provider: ${name}`); } /** * Get current status */ getStatus() { return this.currentStatus; } /** * Set status manually */ setStatus(status) { const oldStatus = this.currentStatus; this.currentStatus = status; if (oldStatus !== status) { this.logger.info(`Status changed: ${oldStatus} -> ${status}`); } } /** * Record a task execution */ recordTask() { this.taskCount++; this.lastTaskTime = Date.now(); } /** * Record an error */ recordError(error) { this.errors.push(`${new Date().toISOString()}: ${error}`); // Keep only last 10 errors if (this.errors.length > 10) { this.errors = this.errors.slice(-10); } // Update status if too many recent errors const recentErrors = this.errors.filter(e => { const errorTime = new Date(e.split(':')[0]).getTime(); return Date.now() - errorTime < 60000; // Last minute }); if (recentErrors.length >= 3) { this.setStatus(performer_1.PerformerStatus.ERROR); } } /** * Set custom metric */ setCustomMetric(key, value) { this.customMetrics.set(key, value); } /** * Get custom metric */ getCustomMetric(key) { return this.customMetrics.get(key); } /** * Perform comprehensive health check */ async performHealthCheck() { const timestamp = Date.now(); let overallHealthy = true; const providerResults = {}; // Run all health check providers for (const [name, provider] of this.providers) { try { const result = await Promise.race([ provider.check(), new Promise((_, reject) => setTimeout(() => reject(new Error('Health check timeout')), this.config.timeout)) ]); providerResults[name] = result; if (!result.healthy) { overallHealthy = false; if (result.error) { this.recordError(`Health check failed [${name}]: ${result.error}`); } } } catch (error) { overallHealthy = false; const errorMsg = error instanceof Error ? error.message : 'Unknown error'; providerResults[name] = { healthy: false, error: errorMsg }; this.recordError(`Health check error [${name}]: ${errorMsg}`); } } // Update failure count and status if (overallHealthy) { this.failures = 0; if (this.currentStatus === performer_1.PerformerStatus.ERROR && this.config.autoRecover) { this.setStatus(performer_1.PerformerStatus.READY_FOR_TASK); } } else { this.failures++; if (this.failures >= this.config.maxFailures) { this.setStatus(performer_1.PerformerStatus.ERROR); } } // Create health check result const result = { status: this.currentStatus, timestamp, details: { uptime: timestamp - this.startTime, memoryUsage: process.memoryUsage(), taskCount: this.taskCount, lastTaskTime: this.lastTaskTime, errors: [...this.errors], }, custom: { providers: providerResults, failures: this.failures, maxFailures: this.config.maxFailures, ...Object.fromEntries(this.customMetrics), }, }; this.lastHealthCheck = result; return result; } /** * Get last health check result */ getLastHealthCheck() { return this.lastHealthCheck; } /** * Get health summary for monitoring */ getHealthSummary() { const memUsage = process.memoryUsage(); return { status: this.currentStatus, uptime: Date.now() - this.startTime, taskCount: this.taskCount, errorCount: this.errors.length, memoryUsageMB: Math.round(memUsage.heapUsed / 1024 / 1024), }; } } exports.HealthManager = HealthManager; //# sourceMappingURL=healthManager.js.map