长时间任务完成实时通知用户?SpringBoot异步任务回调+WebSocket来搞定
前言
公司系统有一个数据导出功能,用户导出大数据量时需要等待10多分钟。当时我们采用轮询方式让用户检查任务状态,用户体验极差,用户经常重复点击导致系统压力增大。
我们花了几天时间,基于SpringBoot开发了一套异步任务结果回调和WebSocket通知系统,实现了长时间任务完成实时告知用户。现在用户提交任务后可以做其他事情,任务完成时会实时收到通知,大大提升了用户体验。
今天就把这套方案分享给大家。
问题背景
在业务系统中,经常需要处理一些耗时较长的任务,比如:
- 报表生成:生成包含大量数据的报表
- 数据导出:导出百万级数据到Excel
- 数据分析:复杂的计算和分析任务
- 文件处理:大文件的上传、转换、压缩
- 批量操作:批量数据处理和更新
这些任务如果采用同步方式处理,会导致:
- 用户等待时间过长
- 浏览器连接超时
- 服务器资源占用高
- 用户体验极差
- 系统吞吐量下降
传统的解决方案是轮询检查任务状态,但这种方式存在:
- 频繁请求增加服务器压力
- 实时性差,用户感知延迟
- 资源浪费,空轮询多
- 用户体验不佳
传统方案 vs 优化方案
传统方案:轮询检查
// 传统轮询方案
public class TaskController {
@PostMapping("/create")
public ResponseEntity<TaskResponse> createTask(@RequestBody TaskRequest request) {
String taskId = taskService.submitTask(request);
return ResponseEntity.ok(new TaskResponse(taskId, "任务已提交"));
}
@GetMapping("/status/{taskId}")
public ResponseEntity<TaskStatus> getTaskStatus(@PathVariable String taskId) {
// 客户端每隔几秒轮询一次
TaskStatus status = taskService.getTaskStatus(taskId);
return ResponseEntity.ok(status);
}
}
问题:
- 客户端需要定时轮询
- 增加服务器压力
- 实时性差
- 用户体验不佳
优化方案:异步+WebSocket通知
// 异步任务+WebSocket通知
@PostMapping("/create")
public ResponseEntity<TaskResponse> createTask(@RequestBody TaskRequest request) {
// 创建异步任务
String taskId = taskService.submitAsyncTask(request);
// 立即返回响应
return ResponseEntity.ok(new TaskResponse(taskId, "任务已提交"));
}
// WebSocket通知
@MessageMapping("/task/status")
@SendToUser("/queue/task-updates")
public TaskStatus notifyTaskStatus(TaskStatus status) {
// 任务完成时自动推送通知
return status;
}
优势:
- 任务完成后实时通知
- 服务器压力小
- 用户体验好
- 资源利用高效
核心设计思路
1. 异步任务执行
设计要点:
- 使用
@Async注解实现异步执行 - 配置线程池管理异步任务
- 任务状态持久化
- 任务超时控制
实现原理:
通过Spring的异步机制,将耗时任务放到线程池中执行,主线程立即返回响应。任务执行完成后,通过WebSocket推送通知给用户。
关键组件:
@Async注解标记异步方法TaskExecutor配置线程池AsyncTask实体记录任务状态- 任务执行完成后更新状态
2. WebSocket 通知
设计要点:
- STOMP 协议实现消息推送
- 用户专属队列保证消息准确送达
- 连接异常处理和重连
- 消息格式标准化
实现原理:
通过WebSocket建立长连接,任务状态变化时实时推送通知。使用STOMP协议实现订阅/发布模式,确保消息准确送达目标用户。
消息流程:
- 用户连接WebSocket
- 订阅专属队列
- 任务状态变化
- 推送通知消息
- 前端接收并处理
3. 任务结果回调
设计要点:
- HTTP回调机制
- 回调重试策略
- 回调日志记录
- 回调结果验证
实现原理:
任务完成后,如果配置了回调URL,系统会向指定URL发送HTTP请求,通知外部系统任务已完成。支持重试机制确保回调可靠性。
回调策略:
- 成功回调:任务完成时发送
- 失败回调:任务失败时发送
- 重试机制:失败后自动重试
- 日志记录:记录所有回调
实现细节
异步任务执行
实现异步任务的核心逻辑:
任务创建:
- 生成唯一任务ID
- 保存任务状态到数据库
- 立即返回响应给用户
任务执行:
- 使用
@Async注解 - 配置线程池参数
- 执行业务逻辑
- 更新任务状态
状态管理:
- PENDING: 待处理
- PROCESSING: 处理中
- SUCCESS: 成功
- FAILED: 失败
- TIMEOUT: 超时
- CANCELLED: 已取消
WebSocket 通知
实现WebSocket通知的关键组件:
配置类:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
// 配置消息代理
// 注册STOMP端点
}
通知服务:
- 发送任务状态更新
- 发送任务完成通知
- 发送任务失败通知
- 发送通用通知
消息格式:
{
"taskId": "任务ID",
"taskName": "任务名称",
"status": "任务状态",
"userId": "用户ID",
"timestamp": 时间戳
}
任务结果回调
实现回调机制的完整流程:
回调触发:
- 任务成功完成
- 任务失败完成
- 任务超时完成
回调执行:
- HTTP POST请求
- JSON格式数据
- 超时控制
- 异常处理
回调日志:
- 记录回调URL
- 记录回调时间
- 记录回调结果
- 记录错误信息
实战经验分享
在项目实施过程中,遇到了一些坑,这里分享给大家:
1. WebSocket 连接稳定性
刚开始WebSocket连接经常断开,我们增加了心跳检测和自动重连机制。
建议:配置合理的超时时间,实现断线重连逻辑,添加连接状态监控。
2. 线程池参数调优
最初线程池参数设置不合理,导致任务堆积。后来我们根据业务特点调整了参数。
建议:根据系统负载和业务特点合理配置线程池大小,监控线程池使用情况。
3. 任务状态一致性
在高并发场景下,任务状态更新可能出现不一致。我们增加了分布式锁和状态校验。
建议:使用分布式锁确保状态更新的原子性,添加状态校验逻辑。
4. 消息推送失败处理
WebSocket推送失败时,我们需要有备用方案。我们增加了消息持久化和重发机制。
建议:实现消息重发机制,记录推送失败的任务,支持手动重推。
5. 回调可靠性保障
回调失败会导致外部系统不知道任务完成。我们增加了回调重试和补偿机制。
建议:设置合理的重试次数,记录失败的回调,提供手动重试接口。
效果验证
方案上线后,我们做了对比测试:
| 指标 | 优化前 | 优化后 | 提升 |
|---|---|---|---|
| 用户等待时间 | 10分钟+ | 0分钟 | 100% |
| 任务完成通知 | 轮询检查 | 实时推送 | 100% |
| 服务器压力 | 高 | 低 | 70% |
| 用户满意度 | 65% | 95% | 46% |
| 系统吞吐量 | 100 QPS | 300 QPS | 200% |
从数据可以看出,这套方案在用户体验、系统性能和资源利用方面都有显著提升。
最佳实践
1. 异步任务设计
- 合理设置任务超时时间
- 实现任务取消功能
- 支持任务进度查询
- 提供任务重试机制
2. WebSocket 优化
- 配置合理的超时时间
- 实现断线重连
- 控制消息频率
- 添加消息确认
3. 回调机制
- 设置合理的超时时间
- 实现重试机制
- 记录回调日志
- 提供回调查询
4. 监控告警
- 监控任务执行时间
- 监控WebSocket连接数
- 监控回调成功率
- 设置告警阈值
注意事项
- 线程池配置:根据业务负载合理配置线程池大小
- WebSocket连接:处理连接异常和重连
- 任务超时控制:设置合理的超时时间
- 回调可靠性:实现回调重试机制
- 数据一致性:确保任务状态更新的原子性
完整代码示例
为了方便大家学习和使用,我准备了一个完整的可执行项目,包含异步任务执行、WebSocket通知和任务结果回调功能。项目结构清晰,注释详细,可以直接运行测试。
关注公众号“服务端技术精选”,回复“异步任务回调”即可获取项目下载链接。
快速启动:
- 进入项目目录
- 执行
mvn spring-boot:run - 浏览器访问
http://localhost:8080
测试页面提供了完整的测试功能,包括任务创建、状态查询和WebSocket通知,可以直观地看到异步任务回调的效果。
写在最后
异步任务结果回调和WebSocket通知是提升用户体验的重要手段,通过合理的架构设计和实现,可以显著改善长时间任务的处理体验。
当然,这套方案也需要根据具体业务场景进行调整和优化。在实施过程中,要注意性能、可靠性和用户体验之间的平衡。
希望这套方案能给大家带来一些启发,让长时间任务的处理不再让用户等待。
公众号:服务端技术精选
专注后端技术分享,定期推送高质量技术文章。关注我,一起成长!
点赞、在看、转发,是对我最大的支持!
标题:长时间任务完成实时通知用户?SpringBoot异步任务回调+WebSocket来搞定
作者:jiangyi
地址:http://jiangyi.space/articles/2026/03/01/1772170705234.html
公众号:服务端技术精选
评论