fix(km): keep backfill reconciler loop alive
All checks were successful
Code Review / ai-code-review (push) Successful in 11s
CD Pipeline / tests (push) Successful in 1m12s
CD Pipeline / build-and-deploy (push) Successful in 4m2s
CD Pipeline / post-deploy-checks (push) Successful in 1m18s

This commit is contained in:
Your Name
2026-05-06 17:03:22 +08:00
parent 73d7e332a4
commit c1ac157aaf
3 changed files with 61 additions and 2 deletions

View File

@@ -25,7 +25,9 @@ Feature Flag
from __future__ import annotations
import asyncio
import json
import structlog
from src.core.config import settings

View File

@@ -16,19 +16,20 @@ P1-1 C1 修復 2026-04-28 ogt + Claude Sonnet 4.6
"""
import json
from unittest.mock import AsyncMock, MagicMock, patch
from unittest.mock import AsyncMock, patch
import pytest
import src.jobs.km_backfill_reconciler_job as reconciler_job
from src.jobs.km_backfill_reconciler_job import (
run_km_backfill_reconciler,
run_km_backfill_reconciler_loop,
)
from src.services.km_writer import (
KM_BACKFILL_DLQ_KEY,
_backfill_path_a_approval_safe,
)
# =============================================================================
# Helper
# =============================================================================
@@ -136,6 +137,32 @@ async def test_reconciler_empty_dlq():
assert result["failed"] == 0
@pytest.mark.asyncio
async def test_reconciler_loop_can_sleep(monkeypatch: pytest.MonkeyPatch):
"""loop 必須能 sleep避免少 import asyncio 導致 background task 啟動即死亡。"""
class StopLoop(Exception):
pass
calls = 0
async def fake_run_once():
nonlocal calls
calls += 1
return {"processed": 0, "success": 0, "failed": 0}
async def fake_sleep(_seconds: int):
raise StopLoop
monkeypatch.setattr(reconciler_job, "run_km_backfill_reconciler", fake_run_once)
monkeypatch.setattr(reconciler_job.asyncio, "sleep", fake_sleep)
with pytest.raises(StopLoop):
await run_km_backfill_reconciler_loop()
assert calls == 1
# =============================================================================
# 5. ENABLE_KM_BACKFILL_RECONCILER=false → 跳過
# =============================================================================

View File

@@ -3858,3 +3858,33 @@ ruff check apps/api/src/core/logging.py apps/api/src/services/failover_alerter.p
### 注意
- `telegram_gateway.py` 全檔仍有大量既有 ruff 債,本次只針對 token 外洩與 MarkdownV2 400 風險做最小安全修補,避免在 6000+ 行 gateway 巨檔混入無關機械改動。
---
## 2026-05-06台北— KM backfill reconciler background loop 修復
**觸發**production API 啟動後出現 `Task exception was never retrieved``run_km_backfill_reconciler_loop()``NameError: name 'asyncio' is not defined` 在第一次 sleep 前死亡,導致 `km:backfill:dlq` 補救 loop 沒有持續運作。
### 已修正
| 範圍 | 結果 |
|------|------|
| `km_backfill_reconciler_job.py` | 補上 `import asyncio`,讓 5 分鐘循環 sleep 可正常執行 |
| 回歸測試 | 新增 `test_reconciler_loop_can_sleep()`,用 fake sleep 主動中止 loop驗證 loop 至少能跑一次 reconciler 並進入 sleep |
### 驗證
```text
pytest apps/api/tests/test_km_writer_backfill_reconciler.py -q
# 8 passed
py_compile apps/api/src/jobs/km_backfill_reconciler_job.py apps/api/tests/test_km_writer_backfill_reconciler.py
# 通過
ruff check apps/api/src/jobs/km_backfill_reconciler_job.py apps/api/tests/test_km_writer_backfill_reconciler.py
# All checks passed
```
### 影響
- KM / PlayBook / RAG 飛輪的 backfill 補救鏈恢復可持續執行,避免 DLQ 堆積後造成知識庫關聯缺口。