80 lines
3.1 KiB
Markdown
80 lines
3.1 KiB
Markdown
# 通用异步任务模块
|
||
|
||
`pjcloud-common-async-task` 提供可由各业务模块复用的异步事务执行、Redis 进度保存和统一进度查询接口。
|
||
|
||
## 接入方式
|
||
|
||
业务模块增加依赖后,Spring Boot 会自动装配 `AsyncTaskExecutorService`、`AsyncTaskProgressService` 和查询接口:
|
||
|
||
```xml
|
||
<dependency>
|
||
<groupId>com.bsd</groupId>
|
||
<artifactId>pjcloud-common-async-task</artifactId>
|
||
</dependency>
|
||
```
|
||
|
||
提交任务时由业务方指定稳定的 Redis 业务命名空间、展示名称和总数。接口同步返回初始进度,业务动作进入公共模块的受控专用线程池并在单个事务中执行:
|
||
|
||
```java
|
||
AsyncTaskProgressVO progress = asyncTaskExecutorService.submit(
|
||
"user:import:teacher", "老师用户导入", users.size(),
|
||
reporter -> users.forEach(user -> {
|
||
importUser(user);
|
||
reporter.advance("正在导入:" + user.getName());
|
||
}));
|
||
```
|
||
|
||
导出等需要在成功终态返回结果文件的任务使用兼容扩展入口,原有无结果任务的 `submit` 契约保持不变:
|
||
|
||
```java
|
||
AsyncTaskProgressVO progress = asyncTaskExecutorService.submitWithResult(
|
||
"user:export", "用户信息导出", 3, reporter -> {
|
||
String fileUrl = exportAndUpload(reporter);
|
||
return AsyncTaskResult.file(fileUrl, "用户信息.xlsx");
|
||
});
|
||
```
|
||
|
||
查询数据本身耗时且提交接口需要立即返回时,可以先用大于零的占位总数创建任务,再在异步线程查询完成后更新真实总数:
|
||
|
||
```java
|
||
AsyncTaskProgressVO progress = asyncTaskExecutorService.submitWithResult(
|
||
"user:export", "用户信息导出", 1, reporter -> {
|
||
List<UserVO> users = queryUsers();
|
||
reporter.updateTotal(users.size(), "已查询 " + users.size() + " 位用户");
|
||
return exportUsers(users, reporter);
|
||
});
|
||
```
|
||
|
||
调用端统一轮询:
|
||
|
||
```text
|
||
GET /async-task/progress?redisKey={业务命名空间}&taskId={任务ID}
|
||
```
|
||
|
||
## Redis 租户 Key 约定
|
||
|
||
项目 Redis 基础设施会根据当前租户上下文自动为 Redis Key 增加租户前缀。业务代码只负责定义业务命名空间和业务唯一标识,**不需要也不得再次手工拼接 `tenantId`**。
|
||
|
||
正确的业务 Key:
|
||
|
||
```text
|
||
async:task:progress:user:import:teacher:{userId}:{taskId}
|
||
```
|
||
|
||
错误的业务 Key:
|
||
|
||
```text
|
||
async:task:progress:user:import:teacher:{tenantId}:{userId}:{taskId}
|
||
```
|
||
|
||
错误示例会导致租户维度重复出现在最终 Redis Key 中,并可能造成同一业务在不同调用方式下无法读取彼此写入的数据。
|
||
|
||
“业务 Key 不拼接租户 ID”不代表异步线程不需要租户上下文。异步任务在访问 Redis、数据库或其他租户资源前,仍需恢复 `TenantContextHolder`,并在任务结束后清理上下文。本模块执行器已经统一处理这一步,业务动作不应重复设置租户上下文。
|
||
|
||
## 事务与进度语义
|
||
|
||
- 整个业务动作由一个 Spring 事务包裹,业务抛出异常时整体回滚。
|
||
- `completed` 表示当前执行位置;失败并回滚时不代表最终成功写入数量。
|
||
- Redis 进度默认保留 24 小时,供页面刷新或短时重连后继续查询。
|
||
- 任务进度按当前登录用户隔离,调用端不能查询其他用户创建的任务。
|