gongxiangp2/docs/upload-cleanup-mechanism.md

6.3 KiB
Raw Blame History

上传临时文件清理机制

概述

系统实现了完整的临时文件清理机制,用于清理断点续传、上传失败、用户取消上传等情况产生的临时文件,防止服务器存储空间被占用。

清理场景

1. 自动清理场景

✅ 上传成功后的清理

  • 位置: app/api/materials/upload/route.ts
  • 时机: 素材成功创建到数据库后
  • 清理内容:
    • 临时合并文件(merged-{fileName})
    • 空临时目录
    • 上传会话记录

✅ 分片合并后的清理

  • 位置: app/api/materials/upload/complete/route.ts
  • 时机: 所有分片合并完成后
  • 清理内容:
    • 所有分片文件(chunk-{index})
    • 保留合并后的文件供正式上传使用

✅ 上传会话过期清理

  • 位置: lib/upload-sessions.ts
  • 机制:
    • Redis模式: 自动过期(8小时TTL)
    • 内存模式: 每小时清理一次过期会话(8小时)

2. 手动清理场景

✅ 用户取消上传

  • 位置: components/UploadModal.tsx → handleCancelBatchUpload()
  • 触发: 用户点击"取消上传"按钮
  • 清理内容:
    • 取消所有进行中的HTTP请求
    • 调用清理API删除临时文件和上传会话
    • 清理前端IndexedDB中的上传状态

✅ 清理API调用

  • 位置: app/api/materials/upload/cleanup/route.ts
  • 方式:
    • POST /api/materials/upload/cleanup: 清理指定的上传会话
    • GET /api/materials/upload/cleanup: 清理所有过期的临时文件

3. 定时清理任务

✅ 定时清理脚本

  • 位置: scripts/cleanup-upload-temp.ts
  • 功能: 清理所有过期或无效的临时上传文件
  • 清理条件:
    • 上传会话已过期(默认8小时)
    • 上传会话不存在(Redis/内存中已删除)
  • 运行方式:
    # 手动运行
    npx tsx scripts/cleanup-upload-temp.ts
    
    # 添加到定时任务(建议每小时运行一次)
    # Linux cron:
    0 * * * * cd /path/to/project && npx tsx scripts/cleanup-upload-temp.ts
    
    # Windows 任务计划程序:
    # 创建定时任务,每小时运行一次
    

临时文件结构

uploads/
└── temp/
    └── {uploadId}/
        ├── meta.json          # 元数据文件(包含创建时间等信息)
        ├── chunk-0            # 分片文件
        ├── chunk-1
        ├── ...
        └── merged-{fileName}  # 合并后的文件(等待正式上传)

清理策略

清理时机

  1. 立即清理(上传成功后)

    • 正式上传成功后立即清理临时合并文件
    • 清理上传会话记录
  2. 用户触发清理(取消上传)

    • 用户点击取消时立即清理
    • 清理所有相关的临时文件和会话
  3. 定时清理(过期文件)

    • 每小时运行一次清理脚本
    • 清理超过24小时的临时文件
    • 清理会话不存在的临时文件

清理条件

文件会被清理的条件:

  • ✅ 上传会话已过期(默认8小时)
  • ✅ 上传会话不存在(Redis/内存中已删除)
  • ✅ 用户主动取消上传
  • ✅ 上传成功完成

文件不会被清理的条件:

  • ❌ 上传会话存在且未过期
  • ❌ 正在上传中的文件(有活跃会话)

API 使用说明

清理指定上传会话

// POST /api/materials/upload/cleanup
const response = await fetch('/api/materials/upload/cleanup', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ uploadId: 'upload-xxx' }),
})

清理所有过期文件

// GET /api/materials/upload/cleanup?expiredOnly=true&maxAge=24
const response = await fetch('/api/materials/upload/cleanup?expiredOnly=true&maxAge=24')

参数说明:

  • uploadId (可选): 指定要清理的上传ID
  • expiredOnly (可选): 是否只清理过期的(默认true)
  • maxAge (可选): 最大年龄(小时),默认24小时

配置说明

环境变量

# 上传目录(临时文件存储位置)
UPLOAD_DIR=./uploads

# 上传会话过期时间(在 upload-sessions.ts 中硬编码为24小时)
# Redis模式:自动过期
# 内存模式:每小时清理一次

清理脚本配置

在 scripts/cleanup-upload-temp.ts 中:

const MAX_AGE_HOURS = 8 // 8小时后清理

监控和日志

清理日志

系统会记录以下清理日志:

[Cleanup] 开始清理临时上传文件...
[Cleanup] 清理上传会话: upload-xxx (过期 25.3小时)
[Cleanup] ✓ 清理成功: 5 个文件, 释放 150.5 MB
[Cleanup] 清理完成:
  - 清理文件数: 10
  - 释放空间: 500.2 MB

错误处理

  • 清理失败不会影响主流程
  • 所有清理错误都会被捕获并记录警告日志
  • 单个文件清理失败不会阻止其他文件的清理

最佳实践

1. 生产环境部署

建议在生产环境中:

  1. 启用Redis存储上传会话

    • 使用 lib/upload-sessions-redis.ts
    • 自动过期机制,无需手动清理会话
  2. 设置定时清理任务

    • 每小时运行一次 scripts/cleanup-upload-temp.ts
    • 使用 cron 或系统定时任务
  3. 监控存储空间

    • 定期检查 uploads/temp/ 目录大小
    • 如果发现异常增长,手动运行清理脚本

2. 开发环境

  • 使用内存Map存储(自动清理过期会话)
  • 可以手动调用清理API测试清理功能

故障排查

问题:临时文件占用空间过大

解决方案:

  1. 检查定时清理任务是否正常运行
  2. 手动运行清理脚本:npx tsx scripts/cleanup-upload-temp.ts
  3. 检查上传会话过期时间设置是否合理

问题:清理后文件仍存在

可能原因:

  1. 文件正在被其他进程使用
  2. 文件权限问题
  3. 清理脚本执行失败

解决方案:

  1. 检查文件是否被锁定
  2. 检查文件权限
  3. 查看清理日志中的错误信息

总结

系统实现了完整的临时文件清理机制:

✅ 自动清理: 上传成功后、分片合并后、会话过期后
✅ 手动清理: 用户取消上传时
✅ 定时清理: 每小时清理过期文件
✅ 错误处理: 清理失败不影响主流程
✅ 日志记录: 详细的清理日志便于监控

这确保了服务器存储空间不会被临时文件占用,同时保证了系统的稳定运行。