fix: skip hedge dispatch when primary finishes during admission

Address branch review findings 1-4 on feature/1.3.7-hedged-requests:

- src/polygateway/middleware/retry.py: recheck primary.done() after
  hedge admission in _attempt_hedged; release the hedge permit via
  settle_and_release(permit, 0) (release_probe for probe entries) and
  adjudicate the primary directly instead of firing a billable HTTP
  request that would be cancelled immediately
- src/polygateway/config.py: check_hedge_assembly raises a hedge-located
  ValueError for empty sources instead of a bare min() error
- tests/unit/test_hedge.py: pin that an injected FakeClock jump of 10^6
  seconds does not trigger hedging (design section 8); pin pick(exclude)
  counting no gate_rejections and leaving reasons untouched; pin silent
  hedge abandonment when the candidate circuit is open; deterministic
  regression for the admission-window race (BlockingLimiter harness)
- tests/unit/test_config.py: assert the empty-sources guard message
  locates the hedge key

Red-to-green evidence in tests/outputs/137/review-fixes/
This commit is contained in:
2026-09-10 14:47:40 -04:00
parent 0572611af7
commit 9f7d407120
4 changed files with 187 additions and 1 deletions
+7
View File
@@ -809,6 +809,13 @@ def check_hedge_assembly(
after = ensure_call_deadline(hedge_after_s, origin)
if after is None:
return None
if not sources:
# 直传路(GatewayClient(sources=[], hedge_after_s=...))没有 settings 的
# 非空守卫先行拦截;报错必须定位到 hedge,而不是裸 min() 空序列异常
raise ValueError(
"hedge_after_s({SCOPE}__HEDGE__AFTER_S)的交叉守卫要求 sources 不能为空;"
"对冲已启用但没有可校验的源"
)
min_timeout = min(s.timeout_s for s in sources)
if after >= min_timeout:
raise ValueError(