CompletableFuture

Java 中 java.util.concurrent 包中的一个类,它提供了一个用于异步编程的强大工具。它可以用来表示一个计算的结果,该计算将在将来的某个时间完成,并且可以通过各种方法来处理当前计算的结果,例如等待计算完成、应用函数来处理结果、组合多个 CompletableFuture 实例,等等。它使得在进行并行或异步操作时更加容易处理异常情况、经济地使用线程以及简化代码的编写。

需求:接口响应时间不确定 需要定义一个时间控制响应时间 设置响应时间和程序等待时间不对等

demo

public String getAnswer(String question, Long dialogId) {
        String userId = tokenService.getLoginUser().getUserId();
        LocalDateTime now = LocalDateTime.now();
        String key = "msgId:" + userId + ":" + now;
        ExecutorService executor = Executors.newSingleThreadExecutor();
        
        CompletableFuture<HttpResponse> future = CompletableFuture.supplyAsync(() -> {
            return HttpRequest.post("********")
                    .timeout(600000)
                    .form("message", question)
                    .execute();
        }, executor);
        //异步等待响应结果 保存到数据库
        future.thenAcceptAsync(message -> {
            synchronized (key) {
                //响应数据 更具msgID判断是否插入还是更新
                Long msgId = redisCache.getCacheObject(key);
                msgId = saveToDatabase(message.body(), dialogId, now, userId, msgId);
                redisCache.setCacheObject(key, msgId, 1, TimeUnit.MINUTES);
                executor.shutdown();
            }
        }, executor).exceptionally(e -> {
            e.printStackTrace();
            executor.shutdown();  // shutdown the executor if an exception occurs
            return null;
        });

        //响应最长等待30秒 没有返回先插入默认数据
        try {
            HttpResponse message = future.get(30, TimeUnit.SECONDS);
            return message.body();
        } catch (TimeoutException e) {
            synchronized (key) {
                Long msgId = redisCache.getCacheObject(key);
                if (msgId == null) {
                    //ai接口未响应 存入默认数据
                    msgId = saveToDatabaseAwait("反应的时间比预期的要长。请稍后刷新试试。", dialogId, now, userId);
                    redisCache.setCacheObject(key, msgId, 1, TimeUnit.MINUTES);
                }
                return "响应时间比预期的要长。请稍后刷新试试。";
            }
        } catch (Exception e) {
            // Handle other exceptions
            e.printStackTrace();
            return "An error occurred.";
        }
    }
public Long saveToDatabase(String aiResp, Long dialogId, LocalDateTime qTime, String userId, Long id) {
        AiDialogMsg aiDialogMsg = AiDialogMsg.builder().build();
        if (id == null) {
            //保存AI消息
            aiDialogMsg = AiDialogMsg.builder().dialogId(dialogId)
                    .content(aiResp)
                    .createTime(qTime)
                    .id(id)
                    .userId(userId)
                    .isAiResp(1)
                    .build();
            aiDialogMsgService.save(aiDialogMsg);
        } else {
            //更新内容
            aiDialogMsg = AiDialogMsg.builder()
                    .content(aiResp)
                    .id(id)
                    .build();
            aiDialogMsgService.updateById(aiDialogMsg);
        }
        return aiDialogMsg.getId();
    }
//未得到响应结果 插入等待数据
    public Long saveToDatabaseAwait(String aiResp, Long dialogId, LocalDateTime qTime, String userId) {
        AiDialogMsg aiDialogMsg = AiDialogMsg.builder().build();
        //保存默认AI消息
        aiDialogMsg = AiDialogMsg.builder().dialogId(dialogId)
                .content(aiResp)
                .createTime(qTime)
                .userId(userId)
                .isAiResp(1)
                .build();
        aiDialogMsgService.save(aiDialogMsg);
        return aiDialogMsg.getId();
    }