fix: insert demoted source after credible alternatives, not at tail

Round 4 showed tail placement routes the third attempt to junk sources
whenever the credible alternative is gate-skipped (tight-RPM source
admitted as credible, then skipped by the limiter, falling through to
the flapping watchdog source). Demoted sources now sit between credible
and non-credible candidates.
This commit is contained in:
2026-07-21 12:08:37 -04:00
parent 0e17f71482
commit dcd386d4aa
2 changed files with 55 additions and 4 deletions
+33 -2
View File
@@ -87,12 +87,43 @@ def _demote_call_failures(
demoted = [s for s in ordered if attempt_fails.get(s.name, 0) >= 2] demoted = [s for s in ordered if attempt_fails.get(s.name, 0) >= 2]
if not demoted or len(demoted) == len(ordered): if not demoted or len(demoted) == len(ordered):
return ordered return ordered
if health is not None: if health is None:
return _move_to_tail(ordered, demoted)
return _health_gated_reorder(ordered, demoted, attempt_fails, health)
def _move_to_tail(ordered: list[SourceConfig], demoted: list[SourceConfig]) -> list[SourceConfig]:
"""无健康视图: 无条件移尾(冷启动保护原语义)。"""
names = {d.name for d in demoted}
return [s for s in ordered if s.name not in names] + demoted
def _health_gated_reorder(
ordered: list[SourceConfig],
demoted: list[SourceConfig],
attempt_fails: dict[str, int],
health: Callable[[str], float],
) -> list[SourceConfig]:
"""健康门槛降权: 无可信替代则原地重试;有则插到可信替代之后。"""
demoted = _credible_demotions(ordered, demoted, attempt_fails, health) demoted = _credible_demotions(ordered, demoted, attempt_fails, health)
if not demoted: if not demoted:
return ordered return ordered
names = {d.name for d in demoted} names = {d.name for d in demoted}
return [s for s in ordered if s.name not in names] + demoted rest = [s for s in ordered if s.name not in names]
return _insert_after_credible(rest, demoted, health)
def _insert_after_credible(
rest: list[SourceConfig],
demoted: list[SourceConfig],
health: Callable[[str], float],
) -> list[SourceConfig]:
"""插入位置(第四轮教训): 被降权源排在可信替代之后、不可信源之前——
可信替代被限流闸/熔断跳过时,下一候选是失败源本身而非垃圾源。"""
bar = 0.5 * max(health(d.name) for d in demoted)
credible = [s for s in rest if health(s.name) >= bar]
junk = [s for s in rest if health(s.name) < bar]
return credible + demoted + junk
def _credible_demotions( def _credible_demotions(
+20
View File
@@ -537,3 +537,23 @@ class TestHealthGatedDemotion:
) )
await mw(_REQ) await mw(_REQ)
assert [n for n, _ in transport.calls] == ["a", "a", "b"] assert [n for n, _ in transport.calls] == ["a", "a", "b"]
class TestDemotionInsertPosition:
"""迭代 3(设计 §3.36 补): 被降权源插在可信替代之后、不可信源之前。"""
async def test_demoted_lands_before_junk_sources(self):
# a 失败 2 次;b 可信(0.9)但会被跳过时,第三候选应是 a 而非垃圾源 c
from polygateway.middleware.retry import _demote_call_failures
srcs = [_src("a"), _src("b"), _src("c")]
health = {"a": 0.9, "b": 0.9, "c": 0.05}.__getitem__
out = _demote_call_failures(srcs, {"a": 2}, health)
assert [s.name for s in out] == ["b", "a", "c"]
async def test_health_blind_demotion_still_tail(self):
from polygateway.middleware.retry import _demote_call_failures
srcs = [_src("a"), _src("b"), _src("c")]
out = _demote_call_failures(srcs, {"a": 2}, None)
assert [s.name for s in out] == ["b", "c", "a"]