fix(rls): 收斂 API DB access context
All checks were successful
Code Review / ai-code-review (push) Successful in 21s
CD Pipeline / tests (push) Successful in 1m20s
CD Pipeline / build-and-deploy (push) Successful in 4m15s
CD Pipeline / post-deploy-checks (push) Successful in 1m58s

This commit is contained in:
Your Name
2026-05-12 19:55:13 +08:00
parent 33c0577e93
commit ff30c61c4c
16 changed files with 327 additions and 55 deletions

View File

@@ -842,14 +842,13 @@ class AIRouter:
空 dict 代表無資料或查詢失敗caller 應降級為忽略)。
"""
try:
from src.db.base import get_session_factory
from src.db.base import get_db_context
from src.repositories.aider_event_repository import AiderEventRepository
except ImportError:
return {}
try:
sf = get_session_factory()
async with sf() as sess:
async with get_db_context() as sess:
repo_obj = AiderEventRepository(sess)
stats = await repo_obj.model_stats_since(days=days)
except Exception:

View File

@@ -28,7 +28,7 @@ from datetime import timedelta
import structlog
from sqlalchemy import func, select, text
from src.db.base import get_session_factory
from src.db.base import get_db_context
from src.db.models import AiGovernanceEvent, AutoRepairExecution, ApprovalRecord
from src.utils.timezone import now_taipei
@@ -127,7 +127,7 @@ class AiSloCalculator:
try:
since = now_taipei() - timedelta(days=SLO_WINDOW_DAYS)
async with get_session_factory()() as session:
async with get_db_context() as session:
slo1 = await self._calc_auto_success_rate(session, since)
slo2 = await self._calc_human_override_rate(session, since)
slo3 = await self._calc_false_neg_rate(session, since)
@@ -210,7 +210,7 @@ class AiSloCalculator:
只在 any_violated=True 時呼叫。不管舊違反是否解決。
"""
try:
async with get_session_factory()() as session:
async with get_db_context() as session:
event = AiGovernanceEvent(
event_type="slo_violation",
details=report.to_dict(),

View File

@@ -1933,14 +1933,14 @@ class DecisionManager:
try:
from src.core.feature_flags import aiops_flags as _p6_flags
if _p6_flags.is_sub_flag_enabled("AIOPS_P6_SELF_DEMOTION"):
from src.db.base import get_session_factory as _p6_sf
from src.db.base import get_db_context as _p6_db_context
from src.db.models import AiGovernanceEvent as _GovernanceEvent
from sqlalchemy import select as _p6_select, func as _p6_func
from datetime import timedelta as _p6_td
_now = __import__("src.utils.timezone", fromlist=["now_taipei"]).now_taipei()
async with _p6_sf()() as _p6_sess:
async with _p6_db_context() as _p6_sess:
# 過去 7 天有幾筆未解決的 slo_violation
_viol_7d_q = await _p6_sess.execute(
_p6_select(_p6_func.count()).where(
@@ -1980,8 +1980,8 @@ class DecisionManager:
)
# 記錄保守模式事件
try:
from src.db.base import get_session_factory as _p6_sf2
async with _p6_sf2()() as _s2:
from src.db.base import get_db_context as _p6_db_context2
async with _p6_db_context2() as _s2:
_s2.add(_GovernanceEvent(
event_type="conservative_mode",
details={
@@ -2021,8 +2021,8 @@ class DecisionManager:
_push_decision_to_telegram(incident, token.proposal_data)
)
try:
from src.db.base import get_session_factory as _p6_sf3
async with _p6_sf3()() as _s3:
from src.db.base import get_db_context as _p6_db_context3
async with _p6_db_context3() as _s3:
_s3.add(_GovernanceEvent(
event_type="self_demotion",
details={

View File

@@ -424,11 +424,10 @@ class DynamicBaselineService:
async def _pg_upsert_baseline(self, state: BaselineState, promql: str, lookback_hours: int) -> None:
"""寫入 DynamicBaselineRecord 到 PostgreSQLINSERT不更新舊記錄"""
try:
from src.db.base import get_session_factory
from src.db.base import get_db_context
from src.db.models import DynamicBaselineRecord
factory = get_session_factory()
async with factory() as session:
async with get_db_context() as session:
record = DynamicBaselineRecord(
metric_name=state.metric_name,
mean=state.mean,
@@ -449,11 +448,10 @@ class DynamicBaselineService:
try:
from sqlalchemy import select
from src.db.base import get_session_factory
from src.db.base import get_db_context
from src.db.models import DynamicBaselineRecord
factory = get_session_factory()
async with factory() as session:
async with get_db_context() as session:
stmt = (
select(DynamicBaselineRecord)
.where(DynamicBaselineRecord.metric_name == metric_name)

View File

@@ -52,7 +52,7 @@ from pathlib import Path
import structlog
from sqlalchemy import and_, select, text as sql_text
from src.db.base import get_session_factory
from src.db.base import get_db_context
from src.db.models import AgentSession, AutoRepairExecution, IncidentEvidence
from src.utils.timezone import now_taipei
@@ -107,9 +107,7 @@ class FineTuneExporter:
async def _run_export(self) -> tuple[str | None, int]:
cutoff = now_taipei() - timedelta(days=EXPORT_LOOKBACK_DAYS)
session_factory = get_session_factory()
async with session_factory() as db:
async with get_db_context() as db:
# 1. 取得成功驗證的 EvidenceSnapshot有 evidence_summary + verification_result='success'
stmt = select(IncidentEvidence).where(
and_(
@@ -153,7 +151,7 @@ class FineTuneExporter:
with open(output_path, 'rb') as _f:
_checksum = hashlib.sha256(_f.read()).hexdigest()
_ids = [str(ev.id) for ev in evidences]
async with session_factory() as _db:
async with get_db_context() as _db:
await _db.execute(
sql_text("""
INSERT INTO finetune_exports (

View File

@@ -296,12 +296,11 @@ class LogAnomalyDetector:
"""
try:
from sqlalchemy.dialects.postgresql import insert as pg_insert
from src.db.base import get_session_factory
from src.db.base import get_db_context
from src.db.models import LogClusterRecord
from src.utils.timezone import now_taipei
factory = get_session_factory()
async with factory() as session:
async with get_db_context() as session:
stmt = pg_insert(LogClusterRecord).values(
cluster_id=cluster.cluster_id,
template=cluster.template,

View File

@@ -39,7 +39,7 @@ from dataclasses import dataclass
import structlog
from sqlalchemy import func, select
from src.db.base import get_session_factory
from src.db.base import get_db_context
from src.db.models import AiGovernanceEvent, PlaybookRecord
from src.utils.timezone import now_taipei
@@ -115,7 +115,7 @@ class TrustDriftDetector:
TrustDistribution樣本不足時 drift_detected=False
"""
try:
async with get_session_factory()() as session:
async with get_db_context() as session:
# 只計算 approved 狀態的 Playbook
total_q = await session.execute(
select(func.count()).where(
@@ -215,7 +215,7 @@ class TrustDriftDetector:
async def save_drift_event(self, dist: TrustDistribution) -> None:
"""將信任度漂移事件寫入 ai_governance_events。"""
try:
async with get_session_factory()() as session:
async with get_db_context() as session:
event = AiGovernanceEvent(
event_type="trust_drift",
details={