""" AI Box Sophon Adapter — 告警记录清理 当告警记录超过配置的 max_records 时,自动清理最早的记录及其关联的视频文件。 """ import logging import os import shutil from sqlalchemy import select, func, asc from .models.orm import AlarmRecord logger = logging.getLogger(__name__) async def trim_alarm_records(db_session, upload_root: str, max_records: int) -> int: """ 裁剪告警记录,保留最新的 max_records 条 删除超出限制的最早记录,同时清理关联的视频文件目录。 Args: db_session: SQLAlchemy 异步 session upload_root: 上传文件根目录(如 ./data/uploads) max_records: 最大保留条数,<= 0 表示不限制 Returns: 实际删除的记录数 """ if max_records <= 0: return 0 # 查询当前总记录数 count_result = await db_session.execute( select(func.count()).select_from(AlarmRecord) ) total = count_result.scalar() or 0 if total <= max_records: return 0 # 超出数量 overflow = total - max_records # 查询最早的 overflow 条记录(按 created_at 升序) stmt = ( select(AlarmRecord) .order_by(asc(AlarmRecord.created_at)) # type: ignore .limit(overflow) ) result = await db_session.execute(stmt) old_records = result.scalars().all() deleted_count = 0 for record in old_records: # 清理关联的视频文件目录 if record.video_file: _delete_video_dir(upload_root, record.video_file) await db_session.delete(record) deleted_count += 1 await db_session.commit() if deleted_count > 0: logger.info( f"[AlarmTrim] 已清理 {deleted_count} 条告警记录 " f"(保留最新 {max_records} 条,原共 {total} 条)" ) return deleted_count def _delete_video_dir(upload_root: str, video_id: str) -> None: """ 删除告警关联的视频文件目录 视频存储路径: {upload_root}/aibox_sophon_adapter/{video_id}/ Args: upload_root: 上传根目录 video_id: 视频唯一标识(VideoId) """ video_dir = os.path.join(upload_root, "aibox_sophon_adapter", video_id) if not os.path.isdir(video_dir): return try: shutil.rmtree(video_dir) logger.debug(f"[AlarmTrim] 已删除视频目录: {video_dir}") except OSError as e: logger.warning(f"[AlarmTrim] 删除视频目录失败 [{video_dir}]: {e}")