fix(sync): не считать сервис с одним IP резервированием
quality / commitlint (push) Skipped
CD / update-wiki (push) Successful in 5s
quality / changes (push) Successful in 9s
quality / docker-check (push) Skipped
quality / web (push) Successful in 1m20s
quality / api (push) Successful in 1m4s
CD / quality (push) Successful in 2m38s
CD / publish (push) Successful in 56s

В payload для VPS Tracker lbMode не отдаём без пула уникальных IP; в UI показываем без резервирования вместо Round robin.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-09-01 15:09:19 +07:00
co-authored by Cursor
parent 7eb195c5d7
commit de3dbe8521
5 changed files with 94 additions and 7 deletions
+15 -2
View File
@@ -3,6 +3,7 @@ import type { CfdmBindingSyncItem, LbMode, ServiceBindingView } from "@cfdm/shar
import { isIpLiteral } from "@cfdm/shared";
import type { Db } from "@cfdm/db";
import { repos, getAppSettingsSecrets, touchVpsTrackerSync } from "@cfdm/db";
import { isSharedPool } from "./routing/pool.js";
export function isLbMode(value: unknown): value is LbMode {
return value === "round_robin" || value === "failover" || value === "weighted";
@@ -18,6 +19,16 @@ export function resolveLbModeForSync(
return undefined;
}
/** Effective HA only when the service has two or more unique origin IPs. */
export function effectiveLbModeForSync(
bindingLbMode: string | undefined | null,
groupLbMode: string | undefined | null,
serviceIps: readonly string[],
): LbMode | undefined {
if (!isSharedPool(serviceIps)) return undefined;
return resolveLbModeForSync(bindingLbMode, groupLbMode);
}
function groupLbModeForService(
db: Db,
serviceId: number,
@@ -166,6 +177,7 @@ export async function buildServiceSyncBindingsAsync(
const items: CfdmBindingSyncItem[] = [];
for (const binding of bindings) {
const ips = await resolveBindingIpsForSync(binding, serviceIps, index, db);
const lbMode = effectiveLbModeForSync(binding.lb_mode, groupLb, serviceIps);
items.push({
bindingId: binding.id,
serviceId: service.id,
@@ -176,7 +188,7 @@ export async function buildServiceSyncBindingsAsync(
hostname: binding.hostname,
ips,
cnameTarget: cnameTargetForSync(binding),
lbMode: resolveLbModeForSync(binding.lb_mode, groupLb),
...(lbMode ? { lbMode } : {}),
});
}
@@ -214,6 +226,7 @@ export async function buildAllSyncBindings(
}
const ips = await resolveBindingIpsForSync(binding, serviceIps, index, db);
const groupLb = groupLbModeForService(db, binding.service_id, groupLbCache);
const lbMode = effectiveLbModeForSync(binding.lb_mode, groupLb, serviceIps);
items.push({
bindingId: binding.id,
serviceId: binding.service_id,
@@ -224,7 +237,7 @@ export async function buildAllSyncBindings(
hostname: binding.hostname,
ips,
cnameTarget: cnameTargetForSync(binding),
lbMode: resolveLbModeForSync(binding.lb_mode, groupLb),
...(lbMode ? { lbMode } : {}),
});
}
return items;
+30
View File
@@ -6,6 +6,7 @@ import {
import {
resolveBindingIpsForSync,
resolveLbModeForSync,
effectiveLbModeForSync,
} from "../src/services/vps-tracker-sync.js";
function binding(
@@ -183,6 +184,35 @@ describe("resolveLbModeForSync", () => {
});
});
describe("effectiveLbModeForSync", () => {
it("omits mode when unique origin IPs are below two", () => {
expect(
effectiveLbModeForSync("round_robin", "failover", ["203.0.113.10"]),
).toBeUndefined();
expect(
effectiveLbModeForSync("round_robin", "failover", [
"203.0.113.10",
"203.0.113.10",
]),
).toBeUndefined();
});
it("emits configured mode when the service has a pool", () => {
expect(
effectiveLbModeForSync("failover", "round_robin", [
"203.0.113.10",
"203.0.113.20",
]),
).toBe("failover");
expect(
effectiveLbModeForSync("off", "weighted", [
"203.0.113.10",
"198.51.100.1",
]),
).toBe("weighted");
});
});
describe("cfdmBindingSyncItemSchema lbMode", () => {
const base = {
bindingId: 1,