From 3d88dfc1c6dd946d903b785de88e3157a34bd514 Mon Sep 17 00:00:00 2001 From: 16337 <1633794139@qq.com> Date: Thu, 5 Mar 2026 17:12:15 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=9A=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E7=AE=97=E6=B3=95=E7=BB=91=E5=AE=9A=E5=90=8E=E8=BE=B9=E7=BC=98?= =?UTF-8?q?=E7=AB=AF=E6=9C=AA=E5=81=9C=E6=AD=A2=E5=AF=B9=E5=BA=94=E7=AE=97?= =?UTF-8?q?=E6=B3=95=E6=8E=A8=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根本原因:config_sync.py 的 _cleanup_stale_records() 方法接收了 incoming_bind_ids 参数但从未使用,导致当 ROI 仍存在但其中某个 算法绑定被删除时,孤立的绑定记录继续留在 SQLite 中,推理循环 仍然从 SQLite 读取到已删除的绑定并继续生成告警。 修复内容: 1. config/database.py: 添加 get_all_bind_ids() 方法 2. core/config_sync.py: 在 _cleanup_stale_records() 中补全 使用 incoming_bind_ids 清理孤立绑定的逻辑 3. algorithms.py: 在 reload_all_algorithms() 中添加清理内存中 孤立算法实例的逻辑,防止内存泄漏 --- algorithms.py | 30 ++++++++++++++++++++++++++++++ config/database.py | 12 +++++++++++- core/config_sync.py | 9 +++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/algorithms.py b/algorithms.py index 9846fe3..ce0e904 100644 --- a/algorithms.py +++ b/algorithms.py @@ -998,9 +998,13 @@ class AlgorithmManager: config_manager = get_config_sync_manager() bindings = config_manager.get_bindings_from_redis("") + # 收集当前配置中有效的 (roi_id, bind_id) 组合 + valid_keys = set() + for bind in bindings: bind_id = bind.get("bind_id") roi_id = bind.get("roi_id") + valid_keys.add((roi_id, bind_id)) if preserve_state: # 仅更新参数,不重置状态 @@ -1012,6 +1016,32 @@ class AlgorithmManager: if self.load_bind_from_redis(bind_id): count += 1 + # 清理内存中已被删除的算法实例 + removed_count = 0 + with self._update_lock: + for roi_id in list(self.algorithms.keys()): + for key in list(self.algorithms[roi_id].keys()): + # key 格式: "roi_id_bind_id" + if key.startswith(roi_id + "_"): + bind_id = key[len(roi_id) + 1:] + if (roi_id, bind_id) not in valid_keys: + for algo in self.algorithms[roi_id][key].values(): + algo.reset() + del self.algorithms[roi_id][key] + # 清除注册缓存 + self._registered_keys = { + k for k in self._registered_keys + if not (k[0] == roi_id and k[1] == bind_id) + } + removed_count += 1 + logger.info(f"清理已删除的算法实例: {key}") + # 如果 roi 下已无算法实例,清理空字典 + if not self.algorithms[roi_id]: + del self.algorithms[roi_id] + + if removed_count > 0: + logger.info(f"已清理 {removed_count} 个孤立算法实例") + logger.info(f"已重新加载 {count} 个算法配置 (preserve_state={preserve_state})") return count except Exception as e: diff --git a/config/database.py b/config/database.py index b1eda4e..d23be56 100644 --- a/config/database.py +++ b/config/database.py @@ -899,7 +899,17 @@ class SQLiteManager: except Exception as e: logger.error(f"删除ROI算法绑定失败: {e}") return 0 - + + def get_all_bind_ids(self) -> List[str]: + """获取所有算法绑定的 bind_id 列表(用于清理孤立绑定)""" + try: + cursor = self._conn.cursor() + cursor.execute("SELECT bind_id FROM roi_algo_bind") + return [row[0] for row in cursor.fetchall()] + except Exception as e: + logger.error(f"获取所有绑定ID失败: {e}") + return [] + def log_config_update( self, config_type: str, diff --git a/core/config_sync.py b/core/config_sync.py index 7bad3e8..75672ae 100644 --- a/core/config_sync.py +++ b/core/config_sync.py @@ -640,6 +640,15 @@ class ConfigSyncManager: removed += 1 + bind_count logger.info(f"清理旧 ROI: {old_roi_id} (含 {bind_count} 条算法绑定)") + # 清理孤立的算法绑定(ROI 仍存在但绑定已被删除的情况) + if incoming_bind_ids: + existing_bind_ids = self._db_manager.get_all_bind_ids() + for old_bind_id in existing_bind_ids: + if old_bind_id not in incoming_bind_ids: + self._db_manager.delete_roi_algo_bind(old_bind_id) + removed += 1 + logger.info(f"清理孤立算法绑定: {old_bind_id}") + if removed > 0: logger.info(f"旧数据清理完成: 共删除 {removed} 条过期记录")