fix(simulation): retry temporary provider proxy failures
This commit is contained in:
@@ -36,6 +36,7 @@ IMAGE_DIGEST_PATTERN: Final = re.compile(r"^sha256:[a-f0-9]{64}$")
|
||||
DEFAULT_CHUNK_BYTES: Final = 8 * 1024 * 1024
|
||||
MAX_JSON_RESPONSE_BYTES: Final = 32 * 1024 * 1024
|
||||
MAX_RETRIES: Final = 3
|
||||
RETRYABLE_PROVIDER_STATUS_CODES: Final = {502, 503, 504}
|
||||
DEFAULT_INGEST_TIMEOUT_SECONDS: Final = 30 * 60.0
|
||||
|
||||
|
||||
@@ -899,7 +900,10 @@ def _validate_runtime_provenance(document: Mapping[str, object]) -> None:
|
||||
|
||||
|
||||
def _unavailable(message: str, error: httpx.HTTPError) -> GaussianPipelineGatewayError:
|
||||
if isinstance(error, httpx.TransportError):
|
||||
if isinstance(error, httpx.TransportError) or (
|
||||
isinstance(error, httpx.HTTPStatusError)
|
||||
and error.response.status_code in RETRYABLE_PROVIDER_STATUS_CODES
|
||||
):
|
||||
return GaussianPipelineUnavailableError(message)
|
||||
return GaussianPipelineGatewayError(message)
|
||||
|
||||
@@ -922,4 +926,6 @@ def _provider_rejection(response: httpx.Response) -> GaussianPipelineGatewayErro
|
||||
message = f"Gaussian provider rejected request (HTTP {response.status_code})"
|
||||
if detail is not None:
|
||||
message = f"{message}: {detail}"
|
||||
if response.status_code in RETRYABLE_PROVIDER_STATUS_CODES:
|
||||
return GaussianPipelineUnavailableError(message)
|
||||
return GaussianPipelineGatewayError(message)
|
||||
|
||||
@@ -14,6 +14,7 @@ from k1link.simulation.gaussian_pipeline_gateway import (
|
||||
GaussianPipelineGateway,
|
||||
GaussianPipelineGatewayError,
|
||||
GaussianPipelineIntegrityError,
|
||||
GaussianPipelineUnavailableError,
|
||||
_discover_bundle_members,
|
||||
)
|
||||
|
||||
@@ -256,6 +257,30 @@ def test_gateway_surfaces_bounded_provider_rejection_detail(tmp_path: Path) -> N
|
||||
))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("status_code", [502, 503, 504])
|
||||
def test_gateway_classifies_temporary_provider_proxy_failures_as_unavailable(
|
||||
tmp_path: Path,
|
||||
status_code: int,
|
||||
) -> None:
|
||||
with (
|
||||
GaussianPipelineGateway(
|
||||
"http://gaussian.test",
|
||||
_token_file(tmp_path),
|
||||
transport=httpx.MockTransport(
|
||||
lambda _request: httpx.Response(
|
||||
status_code,
|
||||
json={"error": "provider_unavailable"},
|
||||
)
|
||||
),
|
||||
) as gateway,
|
||||
pytest.raises(
|
||||
GaussianPipelineUnavailableError,
|
||||
match=rf"HTTP {status_code}.*provider_unavailable",
|
||||
),
|
||||
):
|
||||
gateway.capabilities()
|
||||
|
||||
|
||||
def test_gateway_rejects_incomplete_lcc_bundle(tmp_path: Path) -> None:
|
||||
bundle = tmp_path / "bundle"
|
||||
bundle.mkdir()
|
||||
|
||||
Reference in New Issue
Block a user