这是一份后来补写的设计清单。

场景包括数据导出、日志打包、系统升级、病毒库更新。它们的共同点是:用户通过 HTTP 发起,但任务不应该依赖这条 HTTP 连接活着。

接口应该尽快返回什么

不是文件,也不是一句“正在处理”,而是一个任务 ID:

{
"taskId": "export-20250319-001",
"status": "pending"
}

随后提供任务查询和文件下载接口。前端可以轮询,也可以通过 SSE/WebSocket 接收变化。

后台任务至少要回答这些问题

  • 谁创建的任务?
  • 当前是排队、运行、成功、失败还是取消?
  • 什么时候开始、什么时候结束?
  • 失败原因是什么?
  • 相同参数能否重复创建?
  • 服务重启后,running 状态如何修正?
  • 临时文件多久删除?
  • 文件是否只能由创建者下载?
  • 磁盘空间不足时在哪一步失败?

不要把 goroutine 当成任务系统

在 Handler 里直接 go export() 可以快速异步,但进程重启后没有状态,任务量也没有上限。至少需要持久化任务记录、有界 worker、超时和并发控制。更重要的任务还需要恢复或补偿机制。

系统升级更特殊

升级不仅耗时,还会主动重启自己。上传包需要检查版本、目录结构、重复版本和文件完整性;执行前要备份;重启前要把状态写到进程之外;失败时要留下能够回滚和诊断的信息。

曾经把上传超时放宽到 6 小时,是为了先解决现场大文件无法上传的问题。但超时时间再长,也不能替代任务建模。连接不断只是运气好,状态可恢复才是设计。