feat: isolate live snapshot section deadlines (Closes #1429)
CI / lint (pull_request) Successful in 4m2s
CI / build-release (pull_request) Successful in 7s
CI / browser-journey (pull_request) Successful in 7m12s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy committed 2026-08-26 11:27:35 +00:00
1 parent 065cc46553
commit dc9e64e98e
2 files changed
+115 -16

No files matched your search

+34 -16
View File
@@ -286,6 +286,7 @@ app = FastAPI(title="Stackchain Dashboard", lifespan=lifespan)
app.add_middleware(RequestBodyLimitMiddleware, limit_for=request_body_limit)
app.add_middleware(NegotiatedGZipMiddleware, minimum_size=1_024)
CONTEXT_TIMEOUT_SECONDS = 5.0
LIVE_SNAPSHOT_DEADLINE_GRACE_SECONDS = 0.1
EVENT_STREAM_TIMEOUT_SECONDS = 5.0
READINESS_TIMEOUT_SECONDS = 5.0
READINESS_INTERVAL_SECONDS = max(
@@ -4832,28 +4833,43 @@ async def _load_context_for_user(user_data: dict) -> dict:
async def _build_live_snapshot(sections: set[str] | None = None) -> dict:
requested = set(sections or LIVE_SNAPSHOT_SECTIONS)
results: dict[str, object] = {}
user_data: dict | None = None
user_task: asyncio.Task | None = None
if requested & {"context", "events"}:
user_task = asyncio.create_task(current_user())
async def load_user_section(section: str) -> object:
assert user_task is not None
user_data = await asyncio.shield(user_task)
if not isinstance(user_data, dict) or not user_data.get("login"):
raise ContextPayloadError("Gitea current-user response was invalid")
if section == "context":
return await _load_context_for_user(user_data)
return await activity_events(user_data)
async def load_before_deadline(load: Awaitable[Any]) -> object:
try:
user_data = await current_user()
if not isinstance(user_data, dict) or not user_data.get("login"):
raise ContextPayloadError("Gitea current-user response was invalid")
async with asyncio.timeout(CONTEXT_TIMEOUT_SECONDS):
return await load
except Exception as exc:
for section in requested & {"context", "events"}:
results[section] = exc
return exc
loads: dict[str, Awaitable[Any]] = {}
if "context" in requested and "context" not in results:
assert user_data is not None
loads["context"] = _load_context_for_user(user_data)
if "events" in requested and "events" not in results:
assert user_data is not None
loads["events"] = activity_events(user_data)
if "context" in requested:
loads["context"] = load_user_section("context")
if "events" in requested:
loads["events"] = load_user_section("events")
if "notifications" in requested:
loads["notifications"] = notifications()
if loads:
loaded = await asyncio.gather(*loads.values(), return_exceptions=True)
results.update(zip(loads, loaded))
try:
if loads:
loaded = await asyncio.gather(
*(load_before_deadline(load) for load in loads.values())
)
results.update(zip(loads, loaded))
finally:
if user_task is not None and not user_task.done():
user_task.cancel()
await asyncio.gather(user_task, return_exceptions=True)
context_result = results.get("context")
events_result = results.get("events")
@@ -4892,7 +4908,9 @@ async def _build_live_snapshot(sections: set[str] | None = None) -> dict:
async def _build_live_snapshot_before_deadline(sections: set[str]) -> dict:
async with asyncio.timeout(CONTEXT_TIMEOUT_SECONDS):
async with asyncio.timeout(
CONTEXT_TIMEOUT_SECONDS + LIVE_SNAPSHOT_DEADLINE_GRACE_SECONDS
):
return await _build_live_snapshot(sections)