异步任务问题

2021-01-20 17:42:02 +08:00
 qm332207252

一个接口,接收到一次请求,调用 service 执行异步任务,异步任务执行中,直接返回响应,再次请求该接口或者其他用户请求该接口(更或者是自动任务执行),调用 service,上次请求这个任务还在执行中,因此返回处理中,这种 java 后台有比较好的实现吗?

2076 次点击
所在节点    Java
15 条回复
dqzcwxb
2021-01-20 17:44:51 +08:00
加个锁
stonewu
2021-01-20 17:46:12 +08:00
最简单的方式就是定义一个全局变量
qm332207252
2021-01-20 17:46:46 +08:00
@dqzcwxb 能详细点说明下不
zoharSoul
2021-01-20 17:46:56 +08:00
记到任务表.
qm332207252
2021-01-20 17:47:45 +08:00
@stonewu 我也想过在调用异步方法外面用个什么变量标记执行状态
MicroGalaxy
2021-01-20 17:49:27 +08:00
这种需求还是全局变量最简单好用
qm332207252
2021-01-20 17:58:31 +08:00
@MicroGalaxy 类似前端做登录按钮,请求表格数据什么的异步请求加状态标记那样咯?
killergun
2021-01-20 18:08:48 +08:00
Ticket ?根据 Ticket 来获取进展
guoyuchuan
2021-01-20 18:08:50 +08:00
异步任务可以配置线程池,这样就不会存在你说的这个问题了
guoyuchuan
2021-01-20 18:09:22 +08:00
@guoyuchuan #9 不对,说错了
liian2019
2021-01-20 18:34:58 +08:00
单机就整个 AtomicBoolean,分布式就整个 redis 记一下
RedBeanIce
2021-01-20 19:28:18 +08:00
java 异步任务有很多方法,CompletableFuture.runAsync

至于第二次进来的问题,加个锁就行,楼上有说明,单机和分布式
oneisall8955
2021-01-20 19:36:08 +08:00
单机还是集群,单机配只静态变量,集群搞 redis,加个 key 标识
siweipancc
2021-01-21 11:37:24 +08:00
占坑#
siweipancc
2021-01-21 11:44:00 +08:00
@Log
@RestController
@SpringBootApplication
public class WebApplication {

public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}

static final String CREATED = "create";
static final String PROCESS = "process";
static final String COMPLETE = "complete";


@PostMapping("generate")
public ResponseEntity<Response> generate(@RequestBody Request request) {
return ResponseEntity.ok(generate(request.input, request.taskId));
}


@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Autowired
private ThreadPoolTaskExecutor executor;

@PostConstruct
public void init() {
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
}

Function<UUID, String> valKeyFunc = uuid -> "value::" + uuid;
Duration expire = Duration.ofMinutes(30L);

public Response generate(Integer input, UUID taskId) {

if (taskId == null) {
check(input != null, "请输入值");
UUID uuid = createTask(input);
return new Response(CREATED, null, uuid, expire.getSeconds());
}

String key = valKeyFunc.apply(taskId);
Long expire = redisTemplate.getExpire(key);
Entity value;
try {
value = (Entity) redisTemplate.opsForValue().get(key);
} catch (ClassCastException e) {
log.warning(e.getMessage());
e.printStackTrace();
throw new RuntimeException("服务器内部错误");
}
check(value != null, "任务 " + taskId + " 不存在或者已经过期");
assert value != null;
check(value.complete != null, "服务器内部错误");
if (!value.complete) {
return new Response(PROCESS, null, taskId, expire);
}

return new Response(COMPLETE, value, taskId, expire);
}


private static void check(Boolean condition, String msg) {
if (!Boolean.TRUE.equals(condition)) {
throw new RuntimeException(msg);
}
}


private UUID createTask(Integer input) {
UUID uuid = UUID.randomUUID();
executor.execute(() -> {
try {
Entity entity = new Entity(uuid, false, new Date(), null, input, null);
log.info(String.format("begin task: %s, input: %s", uuid, input));
String key = valKeyFunc.apply(uuid);
redisTemplate.opsForValue().set(key, entity, expire);
log.info(String.format("set task: %s, input: %s, key: %s", uuid, input, key));
TimeUnit.SECONDS.sleep(RandomUtil.randomInt(10, 20));
String value = RandomUtil.randomString(Math.abs(input));
entity.complete = true;
entity.completeTime = new Date();
entity.output = value;
log.info(String.format("end task: %s, input: %s, generated: %s", uuid, input, value));
redisTemplate.opsForValue().set(key, entity, expire);
} catch (InterruptedException e) {
log.warning(e.getMessage());
e.printStackTrace();
}
});
return uuid;
}

@Data
static class Request {
Integer input;
UUID taskId;
}

@AllArgsConstructor
@NoArgsConstructor
@Data
static class Response {
String status;
Object data;
UUID taskId;
Long expire;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
static class Entity {
UUID taskId;
Boolean complete;
Date beginTime;
Date completeTime;

Integer input;
String output;
}

}

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/746768

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX