quality / commitlint (push) Skipped
CD / update-wiki (push) Successful in 8s
quality / changes (push) Successful in 8s
quality / web (push) Skipped
quality / docker-check (push) Skipped
quality / api (push) Successful in 1m20s
CD / quality (push) Successful in 1m31s
CD / publish (push) Successful in 2m4s
Co-authored-by: Cursor <[email protected]>
25 lines
926 B
TypeScript
25 lines
926 B
TypeScript
import type { LbIpRow } from "./types.js";
|
|
import { isPoolMember } from "./health.js";
|
|
|
|
/** Slot length for time-sliced weighted DNS (one A at a time). */
|
|
export const WEIGHTED_SLOT_MS = 60_000;
|
|
|
|
/** Cloudflare DNS-only minimum TTL; Auto (1) is ~300s and would smear ratios. */
|
|
export const WEIGHTED_DNS_TTL = 60;
|
|
|
|
export function weightedDesired(rows: LbIpRow[], nowMs = Date.now()): string[] {
|
|
if (rows.length === 0) return [];
|
|
const live = rows.filter((r) => isPoolMember(r.health));
|
|
const pool = live.length > 0 ? live : rows;
|
|
if (pool.length === 1) return [pool[0]!.ip];
|
|
|
|
const sorted = [...pool].sort((a, b) => a.ip.localeCompare(b.ip));
|
|
const cycle: string[] = [];
|
|
for (const row of sorted) {
|
|
const weight = Math.max(1, Math.round(row.weight));
|
|
for (let i = 0; i < weight; i++) cycle.push(row.ip);
|
|
}
|
|
const slot = Math.floor(nowMs / WEIGHTED_SLOT_MS) % cycle.length;
|
|
return [cycle[slot]!];
|
|
}
|