Kamixitong/docs/license_expiration_fix.md
2025-12-12 11:35:14 +08:00

5.4 KiB
Raw Permalink Blame History

卡密过期状态自动更新方案

问题描述

之前卡密系统存在一个严重问题:卡密激活后即使到期,状态也不会自动更新为"已过期",导致用户可以一直使用已过期的卡密。

问题根源

  1. 只有在用户主动调用 verify() 方法验证时,才会检查过期状态
  2. 如果用户不验证(离线使用、关闭验证等),卡密状态不会更新
  3. 缺少定期检查过期卡密的后台任务

解决方案

1. 新增功能

后台定时任务

  • 每小时检查一次自动将已激活但已过期的卡密状态更新为2已过期
  • 每天凌晨2点:执行全面的卡密健康检查和统计
  • 每周清理:清理过期的审计日志

手动触发接口

管理员可以通过API手动触发检查立即更新过期卡密状态。

2. 文件变更

新增文件

  1. app/utils/background_tasks.py - 后台任务模块

    • update_expired_licenses() - 更新过期卡密状态
    • check_licenses_batch() - 批量检查所有卡密状态
    • cleanup_old_license_logs() - 清理旧日志
  2. app/utils/scheduler.py - 定时任务调度器

    • 管理所有后台定时任务
    • 提供任务状态查询功能

修改文件

  1. requirements.txt - 添加 APScheduler 依赖
  2. app/__init__.py - 应用启动时初始化调度器
  3. app/api/license.py - 新增4个API接口

3. 新增API接口

3.1 手动检查过期卡密

POST /api/v1/licenses/check-expired

权限:管理员

响应示例:

{
  "success": true,
  "message": "成功更新 5 个过期卡密状态",
  "data": {
    "updated_count": 5
  }
}

3.2 批量检查所有卡密状态

POST /api/v1/licenses/batch-check

权限:管理员

响应示例:

{
  "success": true,
  "message": "批量检查完成",
  "data": {
    "active_but_expired": 5,
    "expired_and_marked": 12,
    "active_and_valid": 158,
    "inactive": 45,
    "disabled": 3
  }
}

3.3 获取定时任务状态

GET /api/v1/scheduler/status

权限:管理员

响应示例:

{
  "success": true,
  "data": {
    "running": true,
    "jobs": [
      {
        "id": "update_expired_licenses_hourly",
        "name": "每小时更新过期卡密状态",
        "next_run_time": "2024-01-15T10:00:00",
        "trigger": "interval[1:00:00]"
      },
      {
        "id": "daily_license_health_check",
        "name": "每日卡密健康检查",
        "next_run_time": "2024-01-16T02:00:00",
        "trigger": "cron[hour:2]"
      }
    ]
  }
}

3.4 手动触发定时任务检查

POST /api/v1/scheduler/trigger-check

权限:管理员

响应示例:

{
  "success": true,
  "message": "成功更新 5 个过期卡密状态"
}

部署步骤

1. 安装依赖

pip install APScheduler==3.10.4

2. 重启应用

重启Flask应用调度器会自动启动。

3. 验证部署

  • 查看应用日志,确认调度器启动成功
  • 调用 /api/v1/scheduler/status 查看任务状态
  • 调用 /api/v1/licenses/batch-check 进行一次全面检查

配置选项

禁用调度器

如果需要禁用定时任务,可以设置环境变量:

export DISABLE_SCHEDULER=true

修改检查频率

如需修改定时任务的执行频率,编辑 app/utils/scheduler.py 文件中的调度器配置:

# 每30分钟检查一次
scheduler.add_job(
    func=check_and_update_expired_licenses,
    trigger=IntervalTrigger(minutes=30),
    id='update_expired_licenses_half_hourly',
    name='每30分钟更新过期卡密状态',
    replace_existing=True,
    max_instances=1
)

日志监控

所有定时任务的执行都会记录到应用日志中:

INFO - 开始检查过期卡密...
INFO - 成功更新 5 个过期卡密状态
INFO - 定时任务调度器已启动

测试验证

手动测试步骤

  1. 创建测试卡密

    • 生成一个短期卡密如1天有效期
    • 记录卡密ID
  2. 激活卡密

    • 通过客户端激活卡密
    • 确认状态为1已激活
  3. 模拟过期

    • 修改数据库中的 expire_time 为过去时间
    • 或等待卡密自然过期
  4. 触发检查

    • 调用 POST /api/v1/licenses/check-expired
    • 确认返回更新的卡密数量
  5. 验证状态

    • 查询卡密详情确认状态变为2已过期

自动化测试

可以编写自动化测试脚本,定期调用检查接口并验证结果。

注意事项

  1. 数据库事务:所有状态更新都在事务中执行,确保数据一致性
  2. 错误处理:定时任务失败不会影响应用正常运行
  3. 并发安全:使用 max_instances=1 防止并发执行
  4. 日志记录:所有操作都有审计日志,便于追踪
  5. 性能考虑:大批量更新时,建议分批处理以避免锁表

监控建议

  1. 设置告警:当定时任务连续失败时发送告警
  2. 定期检查:每周查看一次定时任务执行日志
  3. 统计报告:每月统计过期卡密数量和趋势

总结

通过添加后台定时任务和手动触发接口,彻底解决了卡密过期状态不更新的问题。系统现在可以:

自动检测过期卡密并更新状态 提供管理员手动检查接口 记录详细的执行日志 支持灵活的配置和监控

确保用户无法继续使用已过期的卡密,提升了系统的安全性和可靠性。