fix(api): prefilter Runs incident drilldown
Some checks failed
Code Review / ai-code-review (push) Successful in 13s
CD Pipeline / tests (push) Successful in 1m34s
CD Pipeline / build-and-deploy (push) Successful in 5m10s
CD Pipeline / post-deploy-checks (push) Successful in 1m32s
Ansible / Reboot Recovery Contract / validate (push) Has been cancelled
Some checks failed
Code Review / ai-code-review (push) Successful in 13s
CD Pipeline / tests (push) Successful in 1m34s
CD Pipeline / build-and-deploy (push) Successful in 5m10s
CD Pipeline / post-deploy-checks (push) Successful in 1m32s
Ansible / Reboot Recovery Contract / validate (push) Has been cancelled
This commit is contained in:
@@ -992,6 +992,16 @@ async def list_runs(
|
||||
stmt = stmt.where(AwoooPRunState.project_id == project_id)
|
||||
if state is not None:
|
||||
stmt = stmt.where(AwoooPRunState.state == state)
|
||||
if incident_id is not None:
|
||||
incident_run_ids = await _find_run_ids_for_incident_filter(
|
||||
db,
|
||||
project_id=project_id,
|
||||
incident_id=incident_id,
|
||||
limit=max(per_page * 20, _MAX_LIST_CONTEXT_ROWS),
|
||||
)
|
||||
if not incident_run_ids:
|
||||
return {"runs": [], "total": 0, "page": page, "per_page": per_page}
|
||||
stmt = stmt.where(AwoooPRunState.run_id.in_(incident_run_ids))
|
||||
|
||||
offset = (page - 1) * per_page
|
||||
if remediation_status or incident_id or callback_reply_status:
|
||||
@@ -3696,6 +3706,92 @@ def _collect_run_incident_ids(
|
||||
return incident_ids
|
||||
|
||||
|
||||
async def _find_run_ids_for_incident_filter(
|
||||
db: Any,
|
||||
*,
|
||||
project_id: str | None,
|
||||
incident_id: str,
|
||||
limit: int,
|
||||
) -> list[UUID]:
|
||||
"""Pre-filter run ids for a single incident before loading list context.
|
||||
|
||||
The old list filter loaded every run for a project and then searched message
|
||||
sidecars in Python. That becomes too expensive on production-sized history
|
||||
and can turn a single incident drilldown into a gateway timeout.
|
||||
"""
|
||||
|
||||
params: dict[str, Any] = {
|
||||
"incident_id": incident_id,
|
||||
"incident_like": f"%{incident_id}%",
|
||||
"limit": max(int(limit), 1),
|
||||
}
|
||||
project_run_where = ""
|
||||
event_project_where = ""
|
||||
outbound_project_where = ""
|
||||
if project_id is not None:
|
||||
params["project_id"] = project_id
|
||||
project_run_where = "AND r.project_id = :project_id"
|
||||
event_project_where = "AND e.project_id = :project_id"
|
||||
outbound_project_where = "AND m.project_id = :project_id"
|
||||
|
||||
query = text(f"""
|
||||
WITH matched AS (
|
||||
SELECT r.run_id::text AS run_id, r.created_at AS ts
|
||||
FROM awooop_run_state r
|
||||
WHERE (
|
||||
r.trigger_ref ILIKE :incident_like
|
||||
OR r.error_detail ILIKE :incident_like
|
||||
)
|
||||
{project_run_where}
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT e.run_id::text AS run_id, e.received_at AS ts
|
||||
FROM awooop_conversation_event e
|
||||
WHERE e.run_id IS NOT NULL
|
||||
AND (
|
||||
e.source_envelope #> '{{source_refs,incident_ids}}' ? :incident_id
|
||||
OR e.content_preview ILIKE :incident_like
|
||||
OR e.content_redacted ILIKE :incident_like
|
||||
OR e.provider_event_id ILIKE :incident_like
|
||||
)
|
||||
{event_project_where}
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT m.run_id::text AS run_id, COALESCE(m.sent_at, m.queued_at) AS ts
|
||||
FROM awooop_outbound_message m
|
||||
WHERE (
|
||||
m.source_envelope #> '{{source_refs,incident_ids}}' ? :incident_id
|
||||
OR m.source_envelope #> '{{awooop_status_chain,incident_ids}}' ? :incident_id
|
||||
OR m.source_envelope #>> '{{awooop_status_chain,source_id}}' = :incident_id
|
||||
OR m.source_envelope #>> '{{callback_reply,incident_id}}' = :incident_id
|
||||
OR m.content_preview ILIKE :incident_like
|
||||
OR m.content_redacted ILIKE :incident_like
|
||||
OR m.send_error ILIKE :incident_like
|
||||
)
|
||||
{outbound_project_where}
|
||||
)
|
||||
SELECT run_id
|
||||
FROM matched
|
||||
WHERE run_id IS NOT NULL
|
||||
GROUP BY run_id
|
||||
ORDER BY MAX(ts) DESC
|
||||
LIMIT :limit
|
||||
""")
|
||||
result = await db.execute(query, params)
|
||||
run_ids: list[UUID] = []
|
||||
for row in result.mappings().all():
|
||||
raw_run_id = str(row.get("run_id") or "")
|
||||
try:
|
||||
run_id = uuid.UUID(raw_run_id)
|
||||
except ValueError:
|
||||
continue
|
||||
if run_id not in run_ids:
|
||||
run_ids.append(run_id)
|
||||
return run_ids
|
||||
|
||||
|
||||
async def _load_run_message_context(
|
||||
db: Any,
|
||||
runs: list[AwoooPRunState],
|
||||
|
||||
Reference in New Issue
Block a user