/** * ScaleAdvisor * * Monitors service health across the cluster and produces * actionable scaling recommendations. * * This is the "automatic" part of horizontal scaling. Instead of * a human watching dashboards and deciding "billing needs its own * machine", the ScaleAdvisor detects pressure and recommends: * * 1. SCALE UP — add more workers on the same machine * 2. SPLIT OUT — move a service to its own dedicated process * 3. MIGRATE — move a service to another machine * 4. SCALE DOWN — reduce workers or colocate back * * ═══════════════════════════════════════════════════════════════ * SCALING SIGNALS * ═══════════════════════════════════════════════════════════════ * * The advisor monitors three signals per service: * * CPU saturation — is the service's process(es) maxing out? * Latency drift — is P99 latency increasing over time? * Queue pressure — are pending requests growing? * * Thresholds: * * ┌──────────────────┬────────────┬─────────────┬──────────────┐ * │ Signal │ Normal │ Warning │ Critical │ * ├──────────────────┼────────────┼─────────────┼──────────────┤ * │ CPU per worker │ < 60% │ 60-85% │ > 85% │ * │ P99 latency │ < 100ms │ 100-500ms │ > 500ms │ * │ Pending requests │ < 50 │ 50-200 │ > 200 │ * │ Memory per proc │ < 512MB │ 512MB-1GB │ > 1GB │ * └──────────────────┴────────────┴─────────────┴──────────────┘ * * ═══════════════════════════════════════════════════════════════ * DECISION TREE * ═══════════════════════════════════════════════════════════════ * * Service under pressure? * │ * ├─ Is it colocated (sharing a process with others)? * │ └─ YES → Recommendation: SPLIT OUT to its own process * │ (colocation was causing resource contention) * │ * ├─ Does the machine have idle cores? * │ └─ YES → Recommendation: SCALE UP (add more workers) * │ * ├─ Is the MACHINE saturated (all cores busy)? * │ └─ YES → Recommendation: MIGRATE to a new machine * │ (generate deployment command + config change) * │ * └─ Is this a latency problem, not a CPU problem? * └─ YES → Recommendation: check for slow I/O, * add connection pooling, or add caching * * Service underutilized? * │ * ├─ Has it been under 20% CPU for 30+ minutes? * │ └─ Recommendation: SCALE DOWN (reduce workers) * │ * └─ Is it running alone and barely used? * └─ Recommendation: COLOCATE with other light services */ import { EventEmitter } from "node:events"; export type ScaleAction = "scale_up" | "split_out" | "migrate" | "scale_down" | "colocate" | "investigate"; export interface ScaleRecommendation { service: string; action: ScaleAction; reason: string; details: Record; confidence: number; timestamp: number; } interface HealthSnapshot { cpu: number; status: string; workers: number; memory: number; rpcLatencyP99: number; pendingRequests: number; } interface HistoryEntry { timestamp: number; health: HealthSnapshot[]; } interface TopologyInstance { nodeId: string; host: string; transport: string; status: string; cpu: number; memory: number; rpcLatencyP99: number; pendingRequests: number; workers: number; } type Topology = Record; interface CpuThresholds { warning: number; critical: number; scaleDown: number; } interface LatencyThresholds { warning: number; critical: number; } interface PendingThresholds { warning: number; critical: number; } interface MemoryThresholds { warning: number; critical: number; } interface UnderutilizedThresholds { cpu: number; duration: number; } interface Thresholds { cpu: CpuThresholds; latencyP99: LatencyThresholds; pending: PendingThresholds; memory: MemoryThresholds; underutilized: UnderutilizedThresholds; } interface ScaleAdvisorOptions { evaluationIntervalMs?: number; thresholds?: { cpu?: Partial; latencyP99?: Partial; pending?: Partial; memory?: Partial; underutilized?: Partial; }; cooldownMs?: number; scaling?: { autoExecute?: boolean; }; } interface RegistryHealth { cpu?: number; rpcLatencyP99?: number; pendingRequests?: number; memory?: number; status?: string; } interface LocalRegistration { name: string; health: RegistryHealth; metadata?: { group?: string; }; } interface ServiceRegistry { topology(): Topology; nodeId: string; httpBasePort: number; localRegistrations: Map; } export declare class ScaleAdvisor extends EventEmitter { registry: ServiceRegistry; evaluationIntervalMs: number; thresholds: Thresholds; cooldownMs: number; history: Map; maxHistory: number; recommendations: ScaleRecommendation[]; private _autoExecute; private _lastScaleAction; private _timer; private _lastCpuMeasurement; private _lastCpuUsage; private _executor; private _workerCpuReports; constructor(registry: ServiceRegistry, options?: ScaleAdvisorOptions); /** * O3: Set an executor function that actually performs scaling actions. * Called by the Supervisor to provide a callback for auto-scaling. */ setExecutor(fn: (rec: ScaleRecommendation) => Promise): void; /** * O11: Receive a CPU measurement reported by a worker via IPC. * Workers should report their own CPU usage periodically. * RT-H2: Keyed by serviceName:workerId to aggregate per-worker reports. */ reportWorkerCpu(serviceName: string, cpu: number, workerId?: string): void; /** * RT-H2: Get the average CPU across all fresh worker reports for a service. * Returns null if no fresh reports are available. */ private _getAggregatedWorkerCpu; start(): this; stop(): void; /** * Evaluate all services and generate recommendations. */ evaluate(): void; /** * Evaluate a single service instance. */ private _evaluateService; private _cpuRecommendation; private _recordSnapshot; private _lowCpuDuration; private _getMachineCpu; /** * Get current recommendations as a formatted report. */ report(): string; } export {}; //# sourceMappingURL=ScaleAdvisor.d.ts.map