3.1 KiB
LeastBusyStrategy
(no submodules)
Purpose
LeastBusyStrategy selects the eligible worker with the fewest in-flight tasks. When usePerformanceMetrics is enabled it also tracks a rolling-average execution time per worker (success only) and uses it to break ties — preferring faster workers on equal load. The strategy is the right default for heterogeneous pools where worker performance varies but capacity counts are the primary distribution signal.
Features
- Tie-break order: lower
activeTasks→ (optional) loweravgExecutionTime→ highercapacity→ higherweight. notifyTaskCompleted(worker, task, success, durationMs)updates the per-worker EWMA cumulative average; failures are ignored so a flaky worker can't bias selection downward.getWorkerPerformance(id)returns the stored record ornull.resetPerformanceMetrics()clears the registry.setUsePerformanceMetrics(enabled)toggles the flag at runtime;isUsingPerformanceMetrics()reports state.getName()returns"least-busy".
Usage: Basic Example
import { LeastBusyStrategy } from "@suaveplan/queue-distribution/load-balancing/least-busy/least-busy";
const strategy = new LeastBusyStrategy();
// Pool of workers with mixed activeTasks; the one with the fewest wins.
const selected = strategy.selectWorker(pool.getAvailableWorkers());
Usage: Advanced Example
Switch on performance bias when the pool contains a mix of fast and slow nodes (e.g. cross-region workers). The strategy will gradually steer load away from slower nodes.
import { LeastBusyStrategy } from "@suaveplan/queue-distribution/load-balancing/least-busy/least-busy";
const strategy = new LeastBusyStrategy({ usePerformanceMetrics: true });
// As tasks complete, the worker manager feeds outcomes back.
strategy.notifyTaskCompleted(workerA, task, true, 120);
strategy.notifyTaskCompleted(workerB, task, true, 380);
strategy.selectWorker([workerA, workerB]); // prefers A when activeTasks tied
API Reference
class LeastBusyStrategy extends AbstractLoadBalancingStrategy.constructor(options?: { usePerformanceMetrics?: boolean }).selectWorker(workers, task?): Worker | null.notifyTaskCompleted(worker, task, success, durationMs): void.getWorkerPerformance(workerId): LeastBusyPerformanceRecord | null—{ totalExecutionTime, taskCount, avgExecutionTime }.resetPerformanceMetrics(): void.setUsePerformanceMetrics(enabled: boolean): void.isUsingPerformanceMetrics(): boolean.getName(): string— returns"least-busy".
Implementation Notes
Tie-break by capacity then weight (when no performance data is available) prefers larger, more powerful workers — so a freshly added high-capacity worker absorbs additional load even if every worker currently has zero in-flight tasks. The performance map is per-worker keyed by id and persists across pool changes; removing and re-adding a worker with the same id continues the rolling average. If that behaviour is undesirable, call resetPerformanceMetrics() after pool.removeWorker.