Merge pull request 'fix: Bound event stream refresh latency' (#59) from timmy/58-bound-event-stream-refresh-latency into main
This commit is contained in:
commit
36f500d58b
23
src/main.py
23
src/main.py
|
|
@ -14,6 +14,7 @@ from src.views import router as frontend_router
|
||||||
|
|
||||||
app = FastAPI(title="Stackchain Dashboard")
|
app = FastAPI(title="Stackchain Dashboard")
|
||||||
CONTEXT_TIMEOUT_SECONDS = 5.0
|
CONTEXT_TIMEOUT_SECONDS = 5.0
|
||||||
|
EVENT_STREAM_TIMEOUT_SECONDS = 5.0
|
||||||
FRONTEND_DIR = Path(__file__).resolve().parent.parent / "frontend"
|
FRONTEND_DIR = Path(__file__).resolve().parent.parent / "frontend"
|
||||||
|
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
|
|
@ -103,5 +104,23 @@ async def context() -> JSONResponse:
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/v1/events")
|
@app.get("/api/v1/events")
|
||||||
async def event_stream() -> list[dict]:
|
async def event_stream():
|
||||||
return await activity_events()
|
try:
|
||||||
|
return await asyncio.wait_for(
|
||||||
|
activity_events(), timeout=EVENT_STREAM_TIMEOUT_SECONDS
|
||||||
|
)
|
||||||
|
except TimeoutError:
|
||||||
|
return JSONResponse(
|
||||||
|
{
|
||||||
|
"error": (
|
||||||
|
"Gitea event stream request timed out after "
|
||||||
|
f"{EVENT_STREAM_TIMEOUT_SECONDS:g}s"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
status_code=503,
|
||||||
|
headers={
|
||||||
|
"Retry-After": str(
|
||||||
|
max(1, math.ceil(EVENT_STREAM_TIMEOUT_SECONDS))
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
@ -49,6 +51,29 @@ async def test_event_stream_returns_recent_authenticated_gitea_activity(monkeypa
|
||||||
assert response == expected
|
assert response == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.anyio
|
||||||
|
async def test_event_stream_returns_retryable_response_when_gitea_exceeds_deadline(monkeypatch):
|
||||||
|
cancelled = asyncio.Event()
|
||||||
|
|
||||||
|
async def hanging_activity_events():
|
||||||
|
try:
|
||||||
|
await asyncio.Event().wait()
|
||||||
|
finally:
|
||||||
|
cancelled.set()
|
||||||
|
|
||||||
|
monkeypatch.setattr(main, "EVENT_STREAM_TIMEOUT_SECONDS", 0.01)
|
||||||
|
monkeypatch.setattr(main, "activity_events", hanging_activity_events)
|
||||||
|
|
||||||
|
response = await main.event_stream()
|
||||||
|
|
||||||
|
assert response.status_code == 503
|
||||||
|
assert response.headers["retry-after"] == "1"
|
||||||
|
assert json.loads(response.body) == {
|
||||||
|
"error": "Gitea event stream request timed out after 0.01s"
|
||||||
|
}
|
||||||
|
assert cancelled.is_set()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.anyio
|
@pytest.mark.anyio
|
||||||
async def test_activity_events_fetches_feed_for_authenticated_user(monkeypatch):
|
async def test_activity_events_fetches_feed_for_authenticated_user(monkeypatch):
|
||||||
paths = []
|
paths = []
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user