first commit
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
# `LeastBusyStrategy`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## 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) lower `avgExecutionTime` → higher `capacity` → higher `weight`.
|
||||
- `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 or `null`.
|
||||
- `resetPerformanceMetrics()` clears the registry.
|
||||
- `setUsePerformanceMetrics(enabled)` toggles the flag at runtime; `isUsingPerformanceMetrics()` reports state.
|
||||
- `getName()` returns `"least-busy"`.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
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.
|
||||
|
||||
```ts
|
||||
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`.
|
||||
Reference in New Issue
Block a user