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
+35 -4
View File
@@ -87,14 +87,45 @@ def _demote_call_failures(
demoted = [s for s in ordered if attempt_fails.get(s.name, 0) >= 2]
if not demoted or len(demoted) == len(ordered):
return ordered
if health is not None:
demoted = _credible_demotions(ordered, demoted, attempt_fails, health)
if not demoted:
return ordered
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)
if not demoted:
return ordered
names = {d.name for d in 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(
ordered: list[SourceConfig],
demoted: list[SourceConfig],