mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-17 04:12:17 +03:00
fix(combo): rotate unweighted quota-share targets instead of pinning the first
The combo resolver turns an unset step weight into 0 (comboStructure.ts), and #10881 made normalizeWeight treat 0 as disabled plus return definition order when the total weight is 0. A quota-share combo without explicit weights therefore had no DRR quanta and dispatched every request to its first target — the combo-matrix/quota-share integration suite saw openai six times out of six. An all-zero set is now an unweighted combo and shares evenly; an explicit 0 still disables a target when its siblings are weighted. Refs #12732
This commit is contained in:
1
changelog.d/fixes/12732-quota-share-unweighted-drr.md
Normal file
1
changelog.d/fixes/12732-quota-share-unweighted-drr.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(combo):** a `quota-share` combo whose steps carry no weight now rotates across its targets again instead of sending every request to the first one — the resolver turns an unset weight into 0 and #10881 made 0 mean "disabled", so an all-unweighted combo had no quanta and fell back to definition order; an explicit 0 still disables a target next to weighted siblings ([#12732](https://github.com/diegosouzapw/OmniRoute/issues/12732))
|
||||
@@ -180,12 +180,17 @@ function applyDrr(targets: ResolvedComboTarget[], comboName: string): ResolvedCo
|
||||
if (targets.length <= 1) return targets.slice();
|
||||
|
||||
const deficits = getDrrDeficits(comboName);
|
||||
const totalWeight = targets.reduce((sum, t) => sum + normalizeWeight(t.weight), 0);
|
||||
if (totalWeight <= 0) return targets.slice();
|
||||
const weights = targets.map((t) => normalizeWeight(t.weight));
|
||||
const weightedTotal = weights.reduce((sum, w) => sum + w, 0);
|
||||
// A 0 disables a target only relative to weighted siblings. The combo resolver turns an
|
||||
// unset step weight into 0, so an all-zero set is an unweighted combo, not an all-disabled
|
||||
// one: share evenly instead of returning definition order, which pinned the first target.
|
||||
const unweighted = weightedTotal <= 0;
|
||||
const totalWeight = unweighted ? targets.length : weightedTotal;
|
||||
|
||||
// Add each target's quantum (weight share) to its deficit.
|
||||
for (const target of targets) {
|
||||
const quantum = normalizeWeight(target.weight) / totalWeight;
|
||||
for (const [index, target] of targets.entries()) {
|
||||
const quantum = (unweighted ? 1 : weights[index]) / totalWeight;
|
||||
deficits.set(target.executionKey, (deficits.get(target.executionKey) ?? 0) + quantum);
|
||||
}
|
||||
|
||||
|
||||
@@ -282,6 +282,48 @@ describe("DRR: deficit round robin", () => {
|
||||
);
|
||||
});
|
||||
|
||||
test("unweighted steps (weight 0 from the resolver) still alternate instead of pinning the first", () => {
|
||||
// comboStructure resolves a step with no weight to 0, and #10881 made 0 mean "disabled".
|
||||
// With every target at 0 the total weight is 0 and DRR returned definition order, so a
|
||||
// quota-share combo without explicit weights sent every request to its first target.
|
||||
const t1 = makeTarget("ek-unweighted-1", "conn-unweighted-1", 0);
|
||||
const t2 = makeTarget("ek-unweighted-2", "conn-unweighted-2", 0);
|
||||
|
||||
const selected: Array<string | undefined> = [];
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const r = selectQuotaShareTarget(
|
||||
[t1, t2],
|
||||
"combo-unweighted",
|
||||
"anthropic/claude-sonnet-4-5",
|
||||
NOW
|
||||
);
|
||||
selected.push(r.target?.executionKey);
|
||||
r.decrementInflight();
|
||||
}
|
||||
assert.deepEqual(selected, [
|
||||
"ek-unweighted-1",
|
||||
"ek-unweighted-2",
|
||||
"ek-unweighted-1",
|
||||
"ek-unweighted-2",
|
||||
]);
|
||||
});
|
||||
|
||||
test("an explicit weight 0 still disables that target while another target is weighted", () => {
|
||||
const weighted = makeTarget("ek-on", "conn-on", 100);
|
||||
const disabled = makeTarget("ek-off", "conn-off", 0);
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const r = selectQuotaShareTarget(
|
||||
[disabled, weighted],
|
||||
"combo-disabled",
|
||||
"anthropic/claude-sonnet-4-5",
|
||||
NOW
|
||||
);
|
||||
assert.equal(r.target?.executionKey, "ek-on");
|
||||
r.decrementInflight();
|
||||
}
|
||||
});
|
||||
|
||||
test("DRR state is isolated per comboName", () => {
|
||||
const t = makeTarget("ek-shared", "conn-shared", 100);
|
||||
selectQuotaShareTarget([t], "combo-A", "anthropic/claude-sonnet-4-5", NOW);
|
||||
|
||||
Reference in New Issue
Block a user