UNPKG

batch-cluster

Version:
163 lines 6.47 kB
"use strict"; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _ProcessHealthMonitor_healthCheckStates; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProcessHealthMonitor = void 0; const HealthCheckStrategy_1 = require("./HealthCheckStrategy"); const Parser_1 = require("./Parser"); const String_1 = require("./String"); const Task_1 = require("./Task"); /** * Manages health checking logic for processes. * Provides centralized health assessment and monitoring capabilities. */ class ProcessHealthMonitor { constructor(options, emitter, healthStrategy) { this.options = options; this.emitter = emitter; _ProcessHealthMonitor_healthCheckStates.set(this, new Map()); this.healthStrategy = healthStrategy !== null && healthStrategy !== void 0 ? healthStrategy : new HealthCheckStrategy_1.CompositeHealthCheckStrategy(); } /** * Initialize health monitoring for a process */ initializeProcess(pid) { __classPrivateFieldGet(this, _ProcessHealthMonitor_healthCheckStates, "f").set(pid, { lastHealthCheck: Date.now(), healthCheckFailures: 0, lastJobFailed: false, }); } /** * Clean up health monitoring for a process */ cleanupProcess(pid) { __classPrivateFieldGet(this, _ProcessHealthMonitor_healthCheckStates, "f").delete(pid); } /** * Record that a job failed for a process */ recordJobFailure(pid) { const state = __classPrivateFieldGet(this, _ProcessHealthMonitor_healthCheckStates, "f").get(pid); if (state != null) { state.lastJobFailed = true; } } /** * Record that a job succeeded for a process */ recordJobSuccess(pid) { const state = __classPrivateFieldGet(this, _ProcessHealthMonitor_healthCheckStates, "f").get(pid); if (state != null) { state.lastJobFailed = false; } } /** * Assess the health of a process and return why it's not healthy, or null if healthy */ assessHealth(process, overrideReason) { if (overrideReason != null) return overrideReason; const state = __classPrivateFieldGet(this, _ProcessHealthMonitor_healthCheckStates, "f").get(process.pid); if (state != null && state.healthCheckFailures > 0) { return "unhealthy"; } return this.healthStrategy.assess(process, this.options); } /** * Check if a process is healthy */ isHealthy(process, overrideReason) { return this.assessHealth(process, overrideReason) == null; } /** * Assess why a process is not ready (combines health and business) */ assessReadiness(process, overrideReason) { return !process.idle ? "busy" : this.assessHealth(process, overrideReason); } /** * Check if a process is ready to handle tasks */ isReady(process, overrideReason) { return this.assessReadiness(process, overrideReason) == null; } /** * Run a health check on a process if needed */ maybeRunHealthcheck(process) { const hcc = this.options.healthCheckCommand; // if there's no health check command, no-op. if (hcc == null || (0, String_1.blank)(hcc)) return; // if the prior health check failed, .ready will be false if (!this.isReady(process)) return; const state = __classPrivateFieldGet(this, _ProcessHealthMonitor_healthCheckStates, "f").get(process.pid); if (state == null) return; if (state.lastJobFailed || (this.options.healthCheckIntervalMillis > 0 && Date.now() - state.lastHealthCheck > this.options.healthCheckIntervalMillis)) { state.lastHealthCheck = Date.now(); const t = new Task_1.Task(hcc, Parser_1.SimpleParser); t.promise .catch((err) => { this.emitter.emit("healthCheckError", err instanceof Error ? err : new Error(String(err)), // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument process); state.healthCheckFailures++; // BatchCluster will see we're unhealthy and reap us later }) .finally(() => { state.lastHealthCheck = Date.now(); }); // Execute the health check task on the process if (process.execTask(t)) { return t; } } return; } /** * Get health statistics for monitoring */ getHealthStats() { let totalFailures = 0; let processesWithFailures = 0; for (const state of __classPrivateFieldGet(this, _ProcessHealthMonitor_healthCheckStates, "f").values()) { totalFailures += state.healthCheckFailures; if (state.healthCheckFailures > 0) { processesWithFailures++; } } return { monitoredProcesses: __classPrivateFieldGet(this, _ProcessHealthMonitor_healthCheckStates, "f").size, totalHealthCheckFailures: totalFailures, processesWithFailures, }; } /** * Reset health check failures for a process (useful for recovery scenarios) */ resetHealthCheckFailures(pid) { const state = __classPrivateFieldGet(this, _ProcessHealthMonitor_healthCheckStates, "f").get(pid); if (state != null) { state.healthCheckFailures = 0; } } /** * Get health check state for a specific process */ getProcessHealthState(pid) { return __classPrivateFieldGet(this, _ProcessHealthMonitor_healthCheckStates, "f").get(pid); } } exports.ProcessHealthMonitor = ProcessHealthMonitor; _ProcessHealthMonitor_healthCheckStates = new WeakMap(); //# sourceMappingURL=ProcessHealthMonitor.js.map