feat(edifabric): surface retry_after_seconds on quota-blocked responses

EdifabricError now carries an optional retry_after_seconds kwarg
parsed from the upstream Retry-After header (API Management quota
policy always sends this on 429/403 quota responses). The spot-check
driver threads the value into each transport_error entry of
spot-check.json so the operator sees the exact moment quota
replenishes rather than parsing it out of the response body.

Adds a MockTransport test confirming retry_after_seconds is set
when the upstream sends Retry-After. Existing callers are
unaffected (retry_after_seconds defaults to None and is keyword-only).
This commit is contained in:
Nora
2026-07-08 04:08:00 -06:00
parent 56e14341c2
commit 5fe61fddd3
3 changed files with 68 additions and 8 deletions
+22
View File
@@ -136,6 +136,28 @@ def test_validate_interchange_raises_on_5xx():
assert "upstream overloaded" in str(exc_info.value.body)
def test_read_interchange_raises_with_retry_after_when_quota_blocked():
"""On HTTP 403 with a ``Retry-After`` header (API Management quota
policy), the raised EdifabricError exposes ``retry_after_seconds``
so callers can sleep exactly until quota replenishes."""
def handler(request: httpx.Request) -> httpx.Response:
return httpx.Response(
403,
headers={"Retry-After": "50492"},
json={"statusCode": 403,
"message": "Out of call volume quota."},
)
_install_factory(handler)
with pytest.raises(edifabric.EdifabricError) as exc_info:
edifabric.read_interchange(b"ISA*...", api_key=_TEST_KEY)
err = exc_info.value
assert err.status_code == 403
assert err.retry_after_seconds == 50492
assert "Out of call volume quota" in str(err.body)
# --- validate_edi (composed) ------------------------------------------