Skip to content

Commit

Permalink
Merge pull request #288 from opsmill/lgu-fix-url-not-found
Browse files Browse the repository at this point in the history
Raise URLNotFoundError instead of infinite retry
  • Loading branch information
LucasG0 authored Mar 4, 2025
2 parents 0988b2b + fd67def commit 5f02b64
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 5 deletions.
9 changes: 9 additions & 0 deletions docs/docs/python-sdk/reference/config.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,15 @@ The following settings can be defined in the `Config` class
**Default value**: False<br />
**Environment variable**: `INFRAHUB_RETRY_ON_FAILURE`<br />
<!-- vale off -->
## max_retry_duration

**Property**: max_retry_duration<br />
<!-- vale on -->
**Description**: Maximum duration until we stop attempting to retry if enabled.<br />
**Type**: `integer`<br />
**Default value**: 300<br />
**Environment variable**: `INFRAHUB_MAX_RETRY_DURATION`<br />
<!-- vale off -->
## schema_converge_timeout

**Property**: schema_converge_timeout<br />
Expand Down
12 changes: 10 additions & 2 deletions infrahub_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import asyncio
import copy
import logging
import time
from collections.abc import Coroutine, MutableMapping
from functools import wraps
from time import sleep
Expand Down Expand Up @@ -38,6 +39,7 @@
NodeNotFoundError,
ServerNotReachableError,
ServerNotResponsiveError,
URLNotFoundError,
)
from .graphql import Mutation, Query
from .node import (
Expand Down Expand Up @@ -878,7 +880,8 @@ async def execute_graphql(

retry = True
resp = None
while retry:
start_time = time.time()
while retry and time.time() - start_time < self.config.max_retry_duration:
retry = self.retry_on_failure
try:
resp = await self._post(url=url, payload=payload, headers=headers, timeout=timeout)
Expand All @@ -902,6 +905,8 @@ async def execute_graphql(
errors = response.get("errors", [])
messages = [error.get("message") for error in errors]
raise AuthenticationError(" | ".join(messages)) from exc
if exc.response.status_code == 404:
raise URLNotFoundError(url=url)

if not resp:
raise Error("Unexpected situation, resp hasn't been initialized.")
Expand Down Expand Up @@ -1613,7 +1618,8 @@ def execute_graphql(

retry = True
resp = None
while retry:
start_time = time.time()
while retry and time.time() - start_time < self.config.max_retry_duration:
retry = self.retry_on_failure
try:
resp = self._post(url=url, payload=payload, headers=headers, timeout=timeout)
Expand All @@ -1637,6 +1643,8 @@ def execute_graphql(
errors = response.get("errors", [])
messages = [error.get("message") for error in errors]
raise AuthenticationError(" | ".join(messages)) from exc
if exc.response.status_code == 404:
raise URLNotFoundError(url=url)

if not resp:
raise Error("Unexpected situation, resp hasn't been initialized.")
Expand Down
3 changes: 3 additions & 0 deletions infrahub_sdk/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ class ConfigBase(BaseSettings):
pagination_size: int = Field(default=50, description="Page size for queries to the server")
retry_delay: int = Field(default=5, description="Number of seconds to wait until attempting a retry.")
retry_on_failure: bool = Field(default=False, description="Retry operation in case of failure")
max_retry_duration: int = Field(
default=300, description="Maximum duration until we stop attempting to retry if enabled."
)
schema_converge_timeout: int = Field(
default=60, description="Number of seconds to wait for schema to have converged"
)
Expand Down
6 changes: 6 additions & 0 deletions infrahub_sdk/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ def __init__(self, message: str | None = None):
super().__init__(self.message)


class URLNotFoundError(Error):
def __init__(self, url: str):
self.message = f"`{url}` not found."
super().__init__(self.message)


class FeatureNotSupportedError(Error):
"""Raised when trying to use a method on a node that doesn't support it."""

Expand Down
4 changes: 2 additions & 2 deletions tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,6 @@ def generate_infrahubctl(context: Context) -> None:


@task(name="generate-sdk")
def generate_python_sdk(context: Context) -> None:
def generate_python_sdk(context: Context) -> None: # noqa: ARG001
"""Generate documentation for the Python SDK."""
_generate_infrahub_sdk_configuration_documentation(context=context)
_generate_infrahub_sdk_configuration_documentation()
6 changes: 5 additions & 1 deletion tests/integration/test_infrahub_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import pytest

from infrahub_sdk.branch import BranchData
from infrahub_sdk.exceptions import BranchNotFoundError
from infrahub_sdk.exceptions import BranchNotFoundError, URLNotFoundError
from infrahub_sdk.node import InfrahubNode
from infrahub_sdk.schema import ProfileSchemaAPI
from infrahub_sdk.testing.docker import TestInfrahubDockerClient
Expand Down Expand Up @@ -146,6 +146,10 @@ async def test_count_with_filter(self, client: InfrahubClient, base_dataset):
count = await client.count(kind=TESTING_PERSON, name__values=["Liam Walker", "Ethan Carter"])
assert count == 2

async def test_query_unexisting_branch(self, client: InfrahubClient):
with pytest.raises(URLNotFoundError, match=r"/graphql/unexisting` not found."):
await client.execute_graphql(query="unused", branch_name="unexisting")

async def test_create_generic_rel_with_hfid(
self, client: InfrahubClient, base_dataset, cat_luna, person_sophia, schema_animal, schema_cat
):
Expand Down

0 comments on commit 5f02b64

Please sign in to comment.