本卡屬 FR-166(母卡 CM-3109 延伸),決策者 2026-10-28 手測時發現。主 repo(compliance-manager-be)。同批另有「合併第三方元件」卡,兩張不改同一個檔。
白話
弱點資料庫的自動更新檢查是排程每小時排一筆背景工作,由 worker 撿單去連更新站。排單時沒有檢查「上一筆還沒做完」,所以 worker 一停,單子就無限累積:本機 10/25~10/28 沒起 worker,累積了 70 筆一模一樣的檢查單,worker 一起來先花幾十分鐘做重複的檢查,決策者剛跑完的第三方元件掃描排在後面等不到。正式環境 worker 重啟一次也會踩到。
要改成:排程要排新單前,同類型已經有「排隊中」或「執行中」的單,就不排。
問題在哪
- core/plugins/_source_scan_vulndb_fetch.py enqueue_scheduled_check → app/source_scan_vulndb/service/vulndb_settings_app_service.py enqueue_check_update → BackgroundJobQueueAdapter().enqueue:三層都沒查既有單。
- app/background_job/service/background_job_app_service.py 與 infra/background_job/repository/background_job_repo_impl.py 沒有「某類型是否有未完成單」的查詢;只有 claim_next/heartbeat/finish/fail。
怎麼做
- 【extend repo】infra/background_job/repository/background_job_repo_impl.py 加 has_active(job_type, tenant_id=None):status in ('queued','running') 且 attempts < max_attempts 的單存不存在(running 但 lease 過期的算 active,交給 claim_next 回收,不在這裡判)。domain 介面同步加 abstract method。
- 【extend app service】background_job_app_service.py 加 enqueue_if_idle(job_type, payload, max_attempts):有 active 就回 None 並記 info log,沒有才呼叫既有 enqueue。不改既有 enqueue 的行為(手動按「立即檢查」的入口仍可重複排,那是使用者明示)。
- 【extend 排程入口】enqueue_scheduled_check 改走 enqueue_if_idle;手動觸發的 enqueue_check_update 不動。回 None 時排程 log 一行「已有未完成的檢查單,略過」。
- 【順手盤點】grep 其他排程型 enqueue(drive_sync、integrity_spot_check、evidence_classification 的排程入口)是否同樣沒去重;有的話只列在回寫,不在本卡改(避免同批撞檔)。
改哪些檔
- infra/background_job/repository/background_job_repo_impl.py(新 has_active)
- domain/background_job/ 下的 repo 介面(先 ls 找正確檔名;grep 'class IBackgroundJobRepo')
- app/background_job/service/background_job_app_service.py(新 enqueue_if_idle)
- core/plugins/_source_scan_vulndb_fetch.py(enqueue_scheduled_check 改呼叫)
- test/test_fr156_vulndb_fetch.py(既有測試改成走新入口)+ 新增 has_active/enqueue_if_idle 測試
驗證
- 單元測試:已有 queued 單 → enqueue_if_idle 回 None 不新增;已有 running 且 attempts<max → 不新增;已有 failed/done → 新增;attempts 用盡的 running 不算 active。突變:拿掉 has_active 判斷 → 「已有 queued 不新增」那支要紅。