fix: stabilize rule config and cross-review backend
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
import time
|
||||
from fastapi_common.fastapi_common_sqlalchemy.database import GetAsyncSession
|
||||
from fastapi_common.fastapi_common_web.domain.responses import StatusCodeEnum
|
||||
from fastapi_common.fastapi_common_web.exception.LeauditException import LeauditException
|
||||
@@ -25,6 +27,9 @@ from fastapi_modules.fastapi_leaudit.services.impl.ruleGroupSupport import sync_
|
||||
class RuleServiceImpl(IRuleService):
|
||||
"""规则服务实现。"""
|
||||
|
||||
_GLOBAL_LIST_SETS_CACHE: tuple[float, list[RuleSetVO]] | None = None
|
||||
_GLOBAL_RULE_COUNT_CACHE: dict[int, tuple[float, int]] = {}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
OssService: IOssService | None = None,
|
||||
@@ -32,6 +37,21 @@ class RuleServiceImpl(IRuleService):
|
||||
) -> None:
|
||||
self.OssService = OssService or OssServiceImpl()
|
||||
self.Validator = Validator or RuleValidator()
|
||||
self._list_sets_cache = self.__class__._GLOBAL_LIST_SETS_CACHE
|
||||
self._rule_count_cache = self.__class__._GLOBAL_RULE_COUNT_CACHE
|
||||
|
||||
@classmethod
|
||||
def _set_list_sets_cache(cls, value: tuple[float, list[RuleSetVO]] | None) -> None:
|
||||
cls._GLOBAL_LIST_SETS_CACHE = value
|
||||
|
||||
def InvalidateCaches(self, version_ids: list[int] | None = None) -> None:
|
||||
"""清理规则集及规则数量缓存。"""
|
||||
self.__class__._set_list_sets_cache(None)
|
||||
if version_ids is None:
|
||||
self._rule_count_cache.clear()
|
||||
return
|
||||
for version_id in {int(item) for item in version_ids if item is not None}:
|
||||
self._rule_count_cache.pop(version_id, None)
|
||||
|
||||
async def _resolve_unique_child_group_id(self, Session, DocTypeId: int) -> int | None:
|
||||
"""仅当文档类型唯一对应一个二级分组时,返回该分组ID。"""
|
||||
@@ -71,6 +91,11 @@ class RuleServiceImpl(IRuleService):
|
||||
|
||||
async def ListSets(self) -> list[RuleSetVO]:
|
||||
"""列出所有规则集。"""
|
||||
now = time.monotonic()
|
||||
cached = self.__class__._GLOBAL_LIST_SETS_CACHE
|
||||
if cached and now - cached[0] <= 30:
|
||||
return cached[1]
|
||||
|
||||
async with GetAsyncSession() as Session:
|
||||
Result = await Session.execute(
|
||||
text(
|
||||
@@ -114,7 +139,7 @@ class RuleServiceImpl(IRuleService):
|
||||
if usable_version_id is not None and int(usable_version_id) not in usable_counts:
|
||||
usable_counts[int(usable_version_id)] = await self._GetRuleCountByVersionId(int(usable_version_id))
|
||||
|
||||
return [
|
||||
items = [
|
||||
RuleSetVO(
|
||||
id=int(Row["id"]),
|
||||
ruleType=Row["rule_type"],
|
||||
@@ -130,9 +155,18 @@ class RuleServiceImpl(IRuleService):
|
||||
)
|
||||
for Row in rows
|
||||
]
|
||||
cache_value = (time.monotonic(), items)
|
||||
self.__class__._set_list_sets_cache(cache_value)
|
||||
self._list_sets_cache = cache_value
|
||||
return items
|
||||
|
||||
async def _GetRuleCountByVersionId(self, VersionId: int) -> int:
|
||||
"""读取指定可用规则版本的规则数。"""
|
||||
cached = self._rule_count_cache.get(VersionId)
|
||||
now = time.monotonic()
|
||||
if cached and now - cached[0] <= 120:
|
||||
return cached[1]
|
||||
|
||||
async with GetAsyncSession() as Session:
|
||||
Result = await Session.execute(
|
||||
text(
|
||||
@@ -153,7 +187,9 @@ class RuleServiceImpl(IRuleService):
|
||||
try:
|
||||
yaml_text = (await self.OssService.DownloadBytes(Row["oss_url"])).decode("utf-8")
|
||||
validation = self.Validator.ValidateYaml(yaml_text)
|
||||
return int(validation.ruleCount or 0)
|
||||
count = int(validation.ruleCount or 0)
|
||||
self._rule_count_cache[VersionId] = (time.monotonic(), count)
|
||||
return count
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
@@ -786,6 +822,16 @@ class RuleServiceImpl(IRuleService):
|
||||
)
|
||||
await Session.commit()
|
||||
|
||||
self.InvalidateCaches()
|
||||
try:
|
||||
from fastapi_modules.fastapi_leaudit.services.impl.ruleConfigServiceImpl import GetRuleConfigServiceSingleton
|
||||
|
||||
RuleConfigService = GetRuleConfigServiceSingleton()
|
||||
RuleConfigService.InvalidateSummaryCaches()
|
||||
await RuleConfigService.WarmPackSummaries(force=False)
|
||||
except Exception as exc:
|
||||
logging.getLogger("RULE").warning("刷新规则配置摘要缓存失败: %s", exc)
|
||||
|
||||
VersionRow = await self._GetVersion(Session, VersionId)
|
||||
return self._BuildRuleVersionVo(VersionRow)
|
||||
|
||||
@@ -848,3 +894,14 @@ class RuleServiceImpl(IRuleService):
|
||||
"legal_doc": "legal_doc",
|
||||
}
|
||||
return Mapping.get(Prefix, Prefix or "unknown")
|
||||
|
||||
|
||||
_RULE_SERVICE_SINGLETON: RuleServiceImpl | None = None
|
||||
|
||||
|
||||
def GetRuleServiceSingleton() -> RuleServiceImpl:
|
||||
"""返回共享规则服务实例,供控制器与聚合服务复用缓存。"""
|
||||
global _RULE_SERVICE_SINGLETON
|
||||
if _RULE_SERVICE_SINGLETON is None:
|
||||
_RULE_SERVICE_SINGLETON = RuleServiceImpl()
|
||||
return _RULE_SERVICE_SINGLETON
|
||||
|
||||
Reference in New Issue
Block a user