| 1 | import type { HostResourcesSnapshot } from "@t3tools/contracts"; |
| 2 | |
| 3 | /** Callers supply only connected machines hosting the project and selected provider. */ |
| 4 | export function chooseLoadBalancedEnvironment( |
| 5 | candidates: ReadonlyArray<{ |
| 6 | environmentId: string; |
| 7 | resources: HostResourcesSnapshot | null; |
| 8 | /** Client receipt time avoids comparing clocks on different machines. */ |
| 9 | receivedAt?: number; |
| 10 | weight: number; |
| 11 | }>, |
| 12 | now: number, |
| 13 | ): string | null { |
| 14 | let selected: string | null = null; |
| 15 | let bestScore = 0; |
| 16 | for (const { environmentId, resources, receivedAt, weight } of candidates) { |
| 17 | const sampledAt = receivedAt ?? resources?.sampledAt ?? 0; |
| 18 | if ( |
| 19 | !resources || |
| 20 | !Number.isFinite(weight) || |
| 21 | weight <= 0 || |
| 22 | now - sampledAt > 15_000 || |
| 23 | sampledAt > now + 5_000 || |
| 24 | resources.cpuUtilization === null || |
| 25 | resources.cpuUtilization >= 0.95 || |
| 26 | resources.totalMemoryBytes <= 0 || |
| 27 | resources.cpuCount <= 0 |
| 28 | ) { |
| 29 | continue; |
| 30 | } |
| 31 | const memoryAvailable = resources.availableMemoryBytes / resources.totalMemoryBytes; |
| 32 | if (memoryAvailable <= 0.05) continue; |
| 33 | const score = weight * resources.cpuCount * (1 - resources.cpuUtilization) * memoryAvailable; |
| 34 | if (score > bestScore) { |
| 35 | selected = environmentId; |
| 36 | bestScore = score; |
| 37 | } |
| 38 | } |
| 39 | return selected; |
| 40 | } |