fix(agent): degrade runtime receipt query timeouts
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 35s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 35s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
This commit is contained in:
@@ -849,6 +849,7 @@ def _build_runtime_receipt_readback_recovery(
|
||||
db_read_status: str,
|
||||
log_integration_taxonomy: Mapping[str, Any],
|
||||
error_type: str | None,
|
||||
partial_query_failures: Iterable[Mapping[str, Any]] = (),
|
||||
) -> dict[str, Any]:
|
||||
"""Expose the next controlled action when live receipt/log evidence is absent."""
|
||||
|
||||
@@ -867,9 +868,22 @@ def _build_runtime_receipt_readback_recovery(
|
||||
recent_classified_event_total = _int_value(
|
||||
taxonomy_rollups.get("recent_classified_event_total")
|
||||
)
|
||||
db_unavailable = db_read_status != "ok"
|
||||
db_unavailable = db_read_status in {"not_queried", "unavailable"}
|
||||
partial_failures = [dict(item) for item in partial_query_failures]
|
||||
db_partial = db_read_status == "partial"
|
||||
no_live_log_events = classified_event_total <= 0
|
||||
if db_unavailable:
|
||||
if db_partial and not no_live_log_events:
|
||||
status = "degraded_runtime_receipt_partial_query_failures"
|
||||
safe_next_action_id = (
|
||||
"repair_partial_runtime_receipt_queries_then_rerun_log_integration_taxonomy"
|
||||
)
|
||||
safe_next_action_stage = "runtime_receipt_partial_query_recovery"
|
||||
safe_next_action = (
|
||||
"Optimize or fallback the failed receipt queries while keeping successful "
|
||||
"LOG source families visible to KM/RAG/MCP/PlayBook consumers."
|
||||
)
|
||||
blocker_fields = ["partial_query_failures"]
|
||||
elif db_unavailable:
|
||||
status = "blocked_runtime_receipt_db_readback_unavailable"
|
||||
safe_next_action_id = (
|
||||
"repair_runtime_receipt_db_readback_then_rerun_log_integration_taxonomy"
|
||||
@@ -918,6 +932,7 @@ def _build_runtime_receipt_readback_recovery(
|
||||
taxonomy_rollups.get("active_source_family_count")
|
||||
),
|
||||
"inactive_source_family_ids": inactive_source_family_ids,
|
||||
"partial_query_failures": partial_failures,
|
||||
"blocker_fields": blocker_fields,
|
||||
"operation_boundaries": {
|
||||
"readback_only": True,
|
||||
@@ -2141,7 +2156,7 @@ def _build_work_item_progress(
|
||||
"completed"
|
||||
if runtime_truth_complete
|
||||
else "blocked"
|
||||
if db_read_status != "ok"
|
||||
if db_read_status in {"not_queried", "unavailable"}
|
||||
else "in_progress"
|
||||
),
|
||||
"exit_criteria": "production API reports db_read_status=ok and live executor receipts",
|
||||
@@ -2149,7 +2164,9 @@ def _build_work_item_progress(
|
||||
if runtime_truth_complete
|
||||
else (
|
||||
"runtime_receipt_db_readback_unavailable"
|
||||
if db_read_status != "ok"
|
||||
if db_read_status in {"not_queried", "unavailable"}
|
||||
else "runtime_receipt_partial_query_failures"
|
||||
if db_read_status == "partial"
|
||||
else "live_log_classified_event_total_zero"
|
||||
),
|
||||
"db_read_status": db_read_status,
|
||||
@@ -3043,6 +3060,7 @@ def build_runtime_receipt_readback_from_rows(
|
||||
grouped_alert_event_count_rows: Iterable[Mapping[str, Any] | Any] = (),
|
||||
log_controlled_writeback_consumer: Mapping[str, Any] | None = None,
|
||||
error_type: str | None = None,
|
||||
partial_query_failures: Iterable[Mapping[str, Any]] = (),
|
||||
) -> dict[str, Any]:
|
||||
"""Build the live executor receipt readback from already-fetched rows."""
|
||||
|
||||
@@ -3135,6 +3153,7 @@ def build_runtime_receipt_readback_from_rows(
|
||||
db_read_status=db_read_status,
|
||||
log_integration_taxonomy=log_integration_taxonomy,
|
||||
error_type=error_type,
|
||||
partial_query_failures=partial_query_failures,
|
||||
)
|
||||
agent_decision_wiring = _build_agent_decision_wiring(
|
||||
operation_summary=operation_summary,
|
||||
@@ -3198,6 +3217,7 @@ def build_runtime_receipt_readback_from_rows(
|
||||
"project_id": project_id,
|
||||
"lookback_hours": max(1, int(lookback_hours or _DEFAULT_LOOKBACK_HOURS)),
|
||||
"db_read_status": db_read_status,
|
||||
"partial_query_failures": [dict(item) for item in partial_query_failures],
|
||||
"writes_on_read": False,
|
||||
"ansible_operations": {
|
||||
"counts": operation_summary,
|
||||
@@ -3972,11 +3992,15 @@ async def load_ai_agent_autonomous_runtime_receipt_readback(
|
||||
"limit": max(1, int(limit or 20)),
|
||||
}
|
||||
log_controlled_writeback_consumer: dict[str, Any] | None = None
|
||||
partial_query_failures: list[dict[str, str]] = []
|
||||
try:
|
||||
async with get_db_context(project_id) as db:
|
||||
await db.execute(text("SET LOCAL statement_timeout = '5000ms'"))
|
||||
async def _set_statement_timeout() -> None:
|
||||
await db.execute(text("SET LOCAL statement_timeout = '5000ms'"))
|
||||
|
||||
async def _safe_aux_rows(
|
||||
await _set_statement_timeout()
|
||||
|
||||
async def _safe_rows(
|
||||
query_name: str,
|
||||
sql: str,
|
||||
fallback_sql: str | None = None,
|
||||
@@ -3984,89 +4008,131 @@ async def load_ai_agent_autonomous_runtime_receipt_readback(
|
||||
try:
|
||||
return (await db.execute(text(sql), params)).mappings().all()
|
||||
except Exception as exc: # pragma: no cover - depends on live schema drift
|
||||
partial_query_failures.append({
|
||||
"query_name": query_name,
|
||||
"error_type": type(exc).__name__,
|
||||
})
|
||||
logger.warning(
|
||||
"ai_agent_autonomous_runtime_trace_aux_read_failed",
|
||||
"ai_agent_autonomous_runtime_trace_read_failed",
|
||||
project_id=project_id,
|
||||
query_name=query_name,
|
||||
error_type=type(exc).__name__,
|
||||
)
|
||||
rollback = getattr(db, "rollback", None)
|
||||
if callable(rollback):
|
||||
try:
|
||||
await rollback()
|
||||
await _set_statement_timeout()
|
||||
except Exception as reset_exc: # pragma: no cover - live DB state
|
||||
logger.warning(
|
||||
"ai_agent_autonomous_runtime_trace_reset_failed",
|
||||
project_id=project_id,
|
||||
query_name=query_name,
|
||||
error_type=type(reset_exc).__name__,
|
||||
)
|
||||
if fallback_sql:
|
||||
try:
|
||||
return (await db.execute(text(fallback_sql), params)).mappings().all()
|
||||
except Exception as fallback_exc: # pragma: no cover - live schema drift
|
||||
partial_query_failures.append({
|
||||
"query_name": f"{query_name}_fallback",
|
||||
"error_type": type(fallback_exc).__name__,
|
||||
})
|
||||
logger.warning(
|
||||
"ai_agent_autonomous_runtime_trace_aux_fallback_failed",
|
||||
project_id=project_id,
|
||||
query_name=query_name,
|
||||
error_type=type(fallback_exc).__name__,
|
||||
)
|
||||
rollback = getattr(db, "rollback", None)
|
||||
if callable(rollback):
|
||||
try:
|
||||
await rollback()
|
||||
await _set_statement_timeout()
|
||||
except Exception as reset_exc: # pragma: no cover
|
||||
logger.warning(
|
||||
"ai_agent_autonomous_runtime_trace_reset_failed",
|
||||
project_id=project_id,
|
||||
query_name=f"{query_name}_fallback",
|
||||
error_type=type(reset_exc).__name__,
|
||||
)
|
||||
return []
|
||||
|
||||
operation_counts = (
|
||||
await db.execute(text(_RUNTIME_OPERATION_COUNTS_SQL), params)
|
||||
).mappings().all()
|
||||
operation_latest = (
|
||||
await db.execute(text(_RUNTIME_OPERATION_LATEST_SQL), params)
|
||||
).mappings().all()
|
||||
auto_repair_counts = (
|
||||
await db.execute(text(_RUNTIME_AUTO_REPAIR_COUNTS_SQL), params)
|
||||
).mappings().all()
|
||||
auto_repair_latest = (
|
||||
await db.execute(text(_RUNTIME_AUTO_REPAIR_LATEST_SQL), params)
|
||||
).mappings().all()
|
||||
verifier_counts = (
|
||||
await db.execute(text(_RUNTIME_VERIFIER_COUNTS_SQL), params)
|
||||
).mappings().all()
|
||||
verifier_latest = (
|
||||
await db.execute(text(_RUNTIME_VERIFIER_LATEST_SQL), params)
|
||||
).mappings().all()
|
||||
km_counts = (
|
||||
await db.execute(text(_RUNTIME_KM_COUNTS_SQL), params)
|
||||
).mappings().all()
|
||||
km_latest = (
|
||||
await db.execute(text(_RUNTIME_KM_LATEST_SQL), params)
|
||||
).mappings().all()
|
||||
telegram_counts = (
|
||||
await db.execute(text(_RUNTIME_TELEGRAM_COUNTS_SQL), params)
|
||||
).mappings().all()
|
||||
telegram_latest = (
|
||||
await db.execute(text(_RUNTIME_TELEGRAM_LATEST_SQL), params)
|
||||
).mappings().all()
|
||||
mcp_gateway_counts = await _safe_aux_rows(
|
||||
operation_counts = await _safe_rows(
|
||||
"operation_counts",
|
||||
_RUNTIME_OPERATION_COUNTS_SQL,
|
||||
)
|
||||
operation_latest = await _safe_rows(
|
||||
"operation_latest",
|
||||
_RUNTIME_OPERATION_LATEST_SQL,
|
||||
)
|
||||
auto_repair_counts = await _safe_rows(
|
||||
"auto_repair_counts",
|
||||
_RUNTIME_AUTO_REPAIR_COUNTS_SQL,
|
||||
)
|
||||
auto_repair_latest = await _safe_rows(
|
||||
"auto_repair_latest",
|
||||
_RUNTIME_AUTO_REPAIR_LATEST_SQL,
|
||||
)
|
||||
verifier_counts = await _safe_rows(
|
||||
"verifier_counts",
|
||||
_RUNTIME_VERIFIER_COUNTS_SQL,
|
||||
)
|
||||
verifier_latest = await _safe_rows(
|
||||
"verifier_latest",
|
||||
_RUNTIME_VERIFIER_LATEST_SQL,
|
||||
)
|
||||
km_counts = await _safe_rows(
|
||||
"km_counts",
|
||||
_RUNTIME_KM_COUNTS_SQL,
|
||||
)
|
||||
km_latest = await _safe_rows(
|
||||
"km_latest",
|
||||
_RUNTIME_KM_LATEST_SQL,
|
||||
)
|
||||
telegram_counts = await _safe_rows(
|
||||
"telegram_counts",
|
||||
_RUNTIME_TELEGRAM_COUNTS_SQL,
|
||||
)
|
||||
telegram_latest = await _safe_rows(
|
||||
"telegram_latest",
|
||||
_RUNTIME_TELEGRAM_LATEST_SQL,
|
||||
)
|
||||
mcp_gateway_counts = await _safe_rows(
|
||||
"mcp_gateway_counts",
|
||||
_RUNTIME_MCP_GATEWAY_COUNTS_SQL,
|
||||
)
|
||||
legacy_mcp_counts = await _safe_aux_rows(
|
||||
legacy_mcp_counts = await _safe_rows(
|
||||
"legacy_mcp_counts",
|
||||
_RUNTIME_LEGACY_MCP_COUNTS_SQL,
|
||||
)
|
||||
service_log_counts = await _safe_aux_rows(
|
||||
service_log_counts = await _safe_rows(
|
||||
"service_log_counts",
|
||||
_RUNTIME_SERVICE_LOG_COUNTS_SQL,
|
||||
)
|
||||
executor_log_counts = await _safe_aux_rows(
|
||||
executor_log_counts = await _safe_rows(
|
||||
"executor_log_counts",
|
||||
_RUNTIME_EXECUTOR_LOG_COUNTS_SQL,
|
||||
)
|
||||
timeline_counts = await _safe_aux_rows(
|
||||
timeline_counts = await _safe_rows(
|
||||
"timeline_counts",
|
||||
_RUNTIME_TIMELINE_COUNTS_SQL,
|
||||
_RUNTIME_TIMELINE_COUNTS_FALLBACK_SQL,
|
||||
)
|
||||
playbook_trust_counts = await _safe_aux_rows(
|
||||
playbook_trust_counts = await _safe_rows(
|
||||
"playbook_trust_counts",
|
||||
_RUNTIME_PLAYBOOK_TRUST_COUNTS_SQL,
|
||||
_RUNTIME_PLAYBOOK_TRUST_COUNTS_FALLBACK_SQL,
|
||||
)
|
||||
alert_operation_counts = await _safe_aux_rows(
|
||||
alert_operation_counts = await _safe_rows(
|
||||
"alert_operation_counts",
|
||||
_RUNTIME_ALERT_OPERATION_COUNTS_SQL,
|
||||
)
|
||||
alertmanager_event_counts = await _safe_aux_rows(
|
||||
alertmanager_event_counts = await _safe_rows(
|
||||
"alertmanager_event_counts",
|
||||
_RUNTIME_ALERTMANAGER_EVENT_COUNTS_SQL,
|
||||
)
|
||||
grouped_alert_event_counts = await _safe_aux_rows(
|
||||
grouped_alert_event_counts = await _safe_rows(
|
||||
"grouped_alert_event_counts",
|
||||
_RUNTIME_GROUPED_ALERT_EVENT_COUNTS_SQL,
|
||||
)
|
||||
@@ -4097,7 +4163,7 @@ async def load_ai_agent_autonomous_runtime_receipt_readback(
|
||||
return build_runtime_receipt_readback_from_rows(
|
||||
project_id=project_id,
|
||||
lookback_hours=params["lookback_hours"],
|
||||
db_read_status="ok",
|
||||
db_read_status="partial" if partial_query_failures else "ok",
|
||||
operation_count_rows=operation_counts,
|
||||
operation_latest_rows=operation_latest,
|
||||
auto_repair_count_rows=auto_repair_counts,
|
||||
@@ -4118,6 +4184,8 @@ async def load_ai_agent_autonomous_runtime_receipt_readback(
|
||||
alertmanager_event_count_rows=alertmanager_event_counts,
|
||||
grouped_alert_event_count_rows=grouped_alert_event_counts,
|
||||
log_controlled_writeback_consumer=log_controlled_writeback_consumer,
|
||||
error_type="partial_query_failures" if partial_query_failures else None,
|
||||
partial_query_failures=partial_query_failures,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user