Files
wecom_it_smart_desk/backend/scripts/archive_sessions.py
T

86 lines
2.7 KiB
Python

#!/usr/bin/env python3
"""
会话归档脚本
功能:将会话结束超过90天的会话标记为已归档
运行方式:
cd backend
python scripts/archive_sessions.py
定时任务配置(crontab):
# 每天凌晨3点执行
0 3 * * * cd /opt/wecom-it-desk/backend && python scripts/archive_sessions.py >> /var/log/itdesk-archive.log 2>&1
"""
import sys
import os
from datetime import datetime, timedelta, timezone
# 添加 backend 目录到 Python 路径
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from sqlalchemy import create_engine, select, update
from sqlalchemy.orm import Session
from app.config import settings
from app.models.conversation import Conversation
# 归档阈值:会话结束后多少天开始归档(可配置)
ARCHIVE_DAYS = 90
def archive_sessions():
"""将会话结束超过 ARCHIVE_DAYS 天的会话标记为已归档"""
print(f"[{datetime.now()}] 开始执行会话归档任务...")
print(f"归档阈值: {ARCHIVE_DAYS}")
# 使用配置中的数据库 URL
# 注意:本地开发使用 aiosqlite 异步驱动,但脚本是同步的
# 需要将 sqlite+aiosqlite:// 替换为 sqlite://
db_url = settings.database_url.replace("sqlite+aiosqlite://", "sqlite://")
engine = create_engine(db_url)
# 计算归档截止时间:当前时间 - ARCHIVE_DAYS 天
# 只有 resolved_at 早于此时间的会话才会被归档
cutoff_date = datetime.now(timezone.utc) - timedelta(days=ARCHIVE_DAYS)
with Session(engine) as session:
# 查找需要归档的会话:
# 1. 状态为 resolved(已结单)
# 2. 已结单时间(resolved_at 或 updated_at)早于截止时间
# 3. 尚未被归档
stmt = select(Conversation).where(
Conversation.status == "resolved",
Conversation.is_archived == False,
# 使用 updated_at 作为参考(resolved 状态的会话 updated_at 即为结单时间)
Conversation.updated_at < cutoff_date
)
sessions_to_archive = session.execute(stmt).scalars().all()
count = len(sessions_to_archive)
if count == 0:
print(f"[{datetime.now()}] 没有需要归档的会话")
return
print(f"[{datetime.now()}] 找到 {count} 个需要归档的会话")
# 标记为已归档
now = datetime.now(timezone.utc)
for session_obj in sessions_to_archive:
session_obj.is_archived = True
session_obj.archived_at = now
# 提交更改
session.commit()
print(f"[{datetime.now()}] 成功归档 {count} 个会话")
print(f"归档时间: {now.isoformat()}")
if __name__ == "__main__":
archive_sessions()