M39: harden application and acceptance gates
This commit is contained in:
@@ -2,11 +2,12 @@ from __future__ import annotations
|
||||
|
||||
import threading
|
||||
import time
|
||||
from collections.abc import Sequence
|
||||
from datetime import UTC, datetime, timedelta
|
||||
from typing import Literal
|
||||
from typing import Any, Literal
|
||||
|
||||
import httpx
|
||||
from sqlalchemy import func, select
|
||||
from sqlalchemy import Row, func, select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.config import get_settings
|
||||
@@ -38,6 +39,22 @@ _STALE_AFTER = {
|
||||
}
|
||||
|
||||
|
||||
def _latest_rows_per_workflow(db: Session, action: str) -> Sequence[Row[Any]]:
|
||||
"""Return the most recent audit row per workflow name for one action.
|
||||
|
||||
Heartbeats arrive on every scheduled run, so loading *all* rows and picking the
|
||||
latest in Python would grow linearly with deployment age. ``DISTINCT ON`` lets
|
||||
PostgreSQL return exactly one (latest) row per workflow instead.
|
||||
"""
|
||||
workflow_name = AuditEvent.after_json["workflow_name"].astext
|
||||
return db.execute(
|
||||
select(AuditEvent.occurred_at, AuditEvent.after_json, AuditEvent.metadata_json)
|
||||
.where(AuditEvent.action == action)
|
||||
.distinct(workflow_name)
|
||||
.order_by(workflow_name, AuditEvent.occurred_at.desc())
|
||||
).all()
|
||||
|
||||
|
||||
def derive_n8n_status(db: Session) -> N8nIntegrationStatus:
|
||||
counts: dict[str, int] = dict(
|
||||
db.execute(
|
||||
@@ -144,11 +161,7 @@ def derive_n8n_status(db: Session) -> N8nIntegrationStatus:
|
||||
"Fleet Ops — Workflow Error Handler": latest_handler_failure_at,
|
||||
}
|
||||
heartbeat_by_workflow: dict[str, tuple[datetime, str, str | None]] = {}
|
||||
heartbeat_rows = db.execute(
|
||||
select(AuditEvent.occurred_at, AuditEvent.after_json, AuditEvent.metadata_json)
|
||||
.where(AuditEvent.action == "n8n_workflow_heartbeat")
|
||||
.order_by(AuditEvent.occurred_at.desc())
|
||||
).all()
|
||||
heartbeat_rows = _latest_rows_per_workflow(db, "n8n_workflow_heartbeat")
|
||||
for occurred_at, after, metadata in heartbeat_rows:
|
||||
workflow_name = (after or {}).get("workflow_name")
|
||||
if workflow_name in _CANONICAL_WORKFLOWS and workflow_name not in heartbeat_by_workflow:
|
||||
@@ -159,11 +172,7 @@ def derive_n8n_status(db: Session) -> N8nIntegrationStatus:
|
||||
)
|
||||
|
||||
failure_by_workflow: dict[str, tuple[datetime, str | None]] = {}
|
||||
failure_rows = db.execute(
|
||||
select(AuditEvent.occurred_at, AuditEvent.after_json, AuditEvent.metadata_json)
|
||||
.where(AuditEvent.action == "n8n_workflow_failure_registered")
|
||||
.order_by(AuditEvent.occurred_at.desc())
|
||||
).all()
|
||||
failure_rows = _latest_rows_per_workflow(db, "n8n_workflow_failure_registered")
|
||||
for occurred_at, after, metadata in failure_rows:
|
||||
workflow_name = (after or {}).get("workflow_name")
|
||||
if workflow_name in _CANONICAL_WORKFLOWS and workflow_name not in failure_by_workflow:
|
||||
|
||||
Reference in New Issue
Block a user