Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions horizon/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ def __new__(cls, *, prefix=None, is_model=True): # noqa: ARG004
description="URL to the control plane that manages this PDP, typically Permit.io cloud (api.permit.io)",
)

CONTROL_PLANE_TIMEOUT = confi.float(
"CONTROL_PLANE_TIMEOUT",
75,
description="Timeout in seconds for control plane requests",
)

CONTROL_PLANE_PDP_DELTAS_API = confi.str(
"CONTROL_PLANE_PDP_DELTAS_API",
"http://localhost:8000",
Expand Down
1 change: 1 addition & 0 deletions horizon/facts/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def client(self) -> AsyncClient:
env_api_key = get_env_api_key()
self._client = AsyncClient(
base_url=sidecar_config.CONTROL_PLANE,
timeout=sidecar_config.CONTROL_PLANE_TIMEOUT,
headers={"Authorization": f"Bearer {env_api_key}"},
trust_env=True,
)
Expand Down
4 changes: 4 additions & 0 deletions horizon/startup/api_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ class EnvApiKeyFetcher:
def __init__(
self,
backend_url: str = sidecar_config.CONTROL_PLANE,
timeout: float = sidecar_config.CONTROL_PLANE_TIMEOUT,
retry_config=None,
):
self._backend_url = backend_url
self._timeout = timeout
self._retry_config = retry_config or DEFAULT_RETRY_CONFIG
self.api_key_level = self._get_api_key_level()

Expand Down Expand Up @@ -83,6 +85,7 @@ def _fetch_env_key(self, api_key: str, active_project_key: str, active_env_key:
fetch_with_retry = retry(**self._retry_config)(
lambda: BlockingRequest(
token=api_key,
timeout=self._timeout,
).get(url=api_key_url)
)
try:
Expand All @@ -105,6 +108,7 @@ def fetch_scope(self, api_key: str) -> dict | None:
fetch_with_retry = retry(**self._retry_config)(
lambda: BlockingRequest(
token=api_key,
timeout=self._timeout,
).get(url=api_key_url)
)
try:
Expand Down
7 changes: 4 additions & 3 deletions horizon/startup/blocking_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@


class BlockingRequest:
def __init__(self, token: str | None, extra_headers: dict[str, Any] | None = None):
def __init__(self, token: str | None, extra_headers: dict[str, Any] | None = None, timeout: float = 60):
self._token = token
self._extra_headers = {k: v for k, v in (extra_headers or {}).items() if v is not None}
self._timeout = timeout

def _headers(self) -> dict[str, str]:
headers = {}
Expand All @@ -22,7 +23,7 @@ def get(self, url: str, params=None) -> dict:
"""
utility method to send a *blocking* HTTP GET request and get the response back.
"""
response = requests.get(url, headers=self._headers(), params=params)
response = requests.get(url, headers=self._headers(), params=params, timeout=self._timeout)

if response.status_code == 401:
raise InvalidPDPTokenError()
Expand All @@ -33,7 +34,7 @@ def post(self, url: str, payload: dict | None = None, params=None) -> dict:
"""
utility method to send a *blocking* HTTP POST request with a JSON payload and get the response back.
"""
response = requests.post(url, json=payload, headers=self._headers(), params=params)
response = requests.post(url, json=payload, headers=self._headers(), params=params, timeout=self._timeout)

if response.status_code == 401:
raise InvalidPDPTokenError()
Expand Down
11 changes: 9 additions & 2 deletions horizon/startup/remote_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def __init__(
backend_url: str = sidecar_config.CONTROL_PLANE,
remote_config_route: str = sidecar_config.REMOTE_CONFIG_ENDPOINT,
shard_id: str | None = sidecar_config.SHARD_ID,
timeout: float = sidecar_config.CONTROL_PLANE_TIMEOUT,
retry_config=None,
):
"""
Expand All @@ -63,6 +64,7 @@ def __init__(
self._url = f"{backend_url}{remote_config_route}"
self._backend_url = backend_url
self._token = get_env_api_key()
self._timeout = timeout
self._retry_config = retry_config if retry_config is not None else DEFAULT_RETRY_CONFIG
self._shard_id = shard_id

Expand Down Expand Up @@ -91,8 +93,13 @@ def _fetch_config(self) -> RemoteConfig:
However, this is ok because the RemoteConfigFetcher runs *once* when the sidecar starts.
"""
try:
response = BlockingRequest(token=self._token, extra_headers={"X-Shard-ID": self._shard_id}).post(
url=self._url, payload=PersistentStateHandler.build_state_payload_sync()
response = BlockingRequest(
token=self._token,
extra_headers={"X-Shard-ID": self._shard_id},
timeout=self._timeout,
).post(
url=self._url,
payload=PersistentStateHandler.build_state_payload_sync(),
)

try:
Expand Down
1 change: 1 addition & 0 deletions horizon/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ async def _report(self, state: PersistentState | None = None):
config_url = f"{sidecar_config.CONTROL_PLANE}{sidecar_config.REMOTE_STATE_ENDPOINT}"
async with aiohttp.ClientSession(
trust_env=True,
timeout=aiohttp.ClientTimeout(total=sidecar_config.CONTROL_PLANE_TIMEOUT),
) as session:
logger.info("Reporting status update to server...")
response = await session.post(
Expand Down
Loading