mirror of
https://github.com/Routstr/routstr-core.git
synced 2026-08-12 12:13:21 +00:00
Merge pull request #403 from Routstr/fix-admin-routstr-balance-timeout
Handle Routstr admin balance timeouts
This commit is contained in:
+40
-9
@@ -1050,15 +1050,46 @@ async def get_provider_balance(provider_id: int) -> dict[str, object]:
|
||||
if provider.provider_type == "routstr":
|
||||
import httpx
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
clean_url = provider.base_url.rstrip("/")
|
||||
headers = {}
|
||||
if provider.api_key:
|
||||
headers["Authorization"] = f"Bearer {provider.api_key}"
|
||||
resp = await client.get(
|
||||
f"{clean_url}/v1/balance/info",
|
||||
headers=headers,
|
||||
)
|
||||
clean_url = provider.base_url.rstrip("/")
|
||||
headers = {}
|
||||
if provider.api_key:
|
||||
headers["Authorization"] = f"Bearer {provider.api_key}"
|
||||
|
||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
try:
|
||||
resp = await client.get(
|
||||
f"{clean_url}/v1/balance/info",
|
||||
headers=headers,
|
||||
)
|
||||
except httpx.TimeoutException as exc:
|
||||
logger.error(
|
||||
"Timed out fetching Routstr provider balance",
|
||||
extra={
|
||||
"provider_id": provider_id,
|
||||
"base_url": clean_url,
|
||||
"upstream_url": f"{clean_url}/v1/balance/info",
|
||||
"error": str(exc),
|
||||
},
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=504,
|
||||
detail="Timed out contacting upstream Routstr provider",
|
||||
) from exc
|
||||
except httpx.RequestError as exc:
|
||||
logger.error(
|
||||
"Failed to fetch Routstr provider balance",
|
||||
extra={
|
||||
"provider_id": provider_id,
|
||||
"base_url": clean_url,
|
||||
"upstream_url": f"{clean_url}/v1/balance/info",
|
||||
"error": str(exc),
|
||||
},
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=502,
|
||||
detail="Failed to contact upstream Routstr provider",
|
||||
) from exc
|
||||
|
||||
if resp.status_code == 200:
|
||||
data = resp.json()
|
||||
# Return balance in sats
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
from routstr.core.admin import admin_sessions
|
||||
from routstr.core.db import UpstreamProviderRow
|
||||
|
||||
|
||||
async def _create_routstr_provider() -> UpstreamProviderRow:
|
||||
return UpstreamProviderRow(
|
||||
provider_type="routstr",
|
||||
base_url="https://upstream.example",
|
||||
api_key="",
|
||||
enabled=True,
|
||||
)
|
||||
|
||||
|
||||
def _admin_headers() -> dict[str, str]:
|
||||
token = "test-admin-token"
|
||||
admin_sessions[token] = int(
|
||||
(datetime.now(timezone.utc) + timedelta(minutes=5)).timestamp()
|
||||
)
|
||||
return {"Authorization": f"Bearer {token}"}
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_routstr_provider_balance_timeout_returns_504(
|
||||
integration_client: httpx.AsyncClient,
|
||||
integration_session: AsyncSession,
|
||||
) -> None:
|
||||
provider = await _create_routstr_provider()
|
||||
integration_session.add(provider)
|
||||
await integration_session.commit()
|
||||
await integration_session.refresh(provider)
|
||||
|
||||
request = httpx.Request("GET", f"{provider.base_url}/v1/balance/info")
|
||||
timeout_error = httpx.ConnectTimeout("Connect timeout", request=request)
|
||||
|
||||
with patch(
|
||||
"httpx.AsyncHTTPTransport.handle_async_request",
|
||||
new=AsyncMock(side_effect=timeout_error),
|
||||
):
|
||||
response = await integration_client.get(
|
||||
f"/admin/api/upstream-providers/{provider.id}/balance",
|
||||
headers=_admin_headers(),
|
||||
)
|
||||
|
||||
assert response.status_code == 504
|
||||
assert response.json()["detail"] == "Timed out contacting upstream Routstr provider"
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_routstr_provider_balance_request_error_returns_502(
|
||||
integration_client: httpx.AsyncClient,
|
||||
integration_session: AsyncSession,
|
||||
) -> None:
|
||||
provider = await _create_routstr_provider()
|
||||
integration_session.add(provider)
|
||||
await integration_session.commit()
|
||||
await integration_session.refresh(provider)
|
||||
|
||||
request = httpx.Request("GET", f"{provider.base_url}/v1/balance/info")
|
||||
request_error = httpx.ConnectError("Connection failed", request=request)
|
||||
|
||||
with patch(
|
||||
"httpx.AsyncHTTPTransport.handle_async_request",
|
||||
new=AsyncMock(side_effect=request_error),
|
||||
):
|
||||
response = await integration_client.get(
|
||||
f"/admin/api/upstream-providers/{provider.id}/balance",
|
||||
headers=_admin_headers(),
|
||||
)
|
||||
|
||||
assert response.status_code == 502
|
||||
assert response.json()["detail"] == "Failed to contact upstream Routstr provider"
|
||||
Reference in New Issue
Block a user