一个接口,接收到一次请求,调用 service 执行异步任务,异步任务执行中,直接返回响应,再次请求该接口或者其他用户请求该接口(更或者是自动任务执行),调用 service,上次请求这个任务还在执行中,因此返回处理中,这种 java 后台有比较好的实现吗?
1
dqzcwxb 2021-01-20 17:44:51 +08:00
加个锁
|
2
stonewu 2021-01-20 17:46:12 +08:00
最简单的方式就是定义一个全局变量
|
3
qm332207252 OP @dqzcwxb 能详细点说明下不
|
4
zoharSoul 2021-01-20 17:46:56 +08:00
记到任务表.
|
5
qm332207252 OP @stonewu 我也想过在调用异步方法外面用个什么变量标记执行状态
|
6
MicroGalaxy 2021-01-20 17:49:27 +08:00
这种需求还是全局变量最简单好用
|
7
qm332207252 OP @MicroGalaxy 类似前端做登录按钮,请求表格数据什么的异步请求加状态标记那样咯?
|
8
killergun 2021-01-20 18:08:48 +08:00
Ticket ?根据 Ticket 来获取进展
|
9
guoyuchuan 2021-01-20 18:08:50 +08:00
异步任务可以配置线程池,这样就不会存在你说的这个问题了
|
10
guoyuchuan 2021-01-20 18:09:22 +08:00
@guoyuchuan #9 不对,说错了
|
11
liian2019 2021-01-20 18:34:58 +08:00
单机就整个 AtomicBoolean,分布式就整个 redis 记一下
|
12
RedBeanIce 2021-01-20 19:28:18 +08:00
java 异步任务有很多方法,CompletableFuture.runAsync
至于第二次进来的问题,加个锁就行,楼上有说明,单机和分布式 |
13
oneisall8955 2021-01-20 19:36:08 +08:00 via Android
单机还是集群,单机配只静态变量,集群搞 redis,加个 key 标识
|
14
siweipancc 2021-01-21 11:37:24 +08:00 via iPhone
占坑#
|
15
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; } } |