Administrator
Administrator
发布于 2025-02-14 / 57 阅读
0
1

记录一次webFlux 无法输出bug

使用一次webflux调用大模型时,没有返回数据,我的代码如下

    public void dealData(String message, String sessionId) {
        ...省略无用业务代码
        Flux<String> result = deepseek(param, sessionId, sb);
        System.out.println(result);
    }

    private Flux<String> deepseek(JSONObject param, String sessionId,  StringBuffer sb) {
        return webClient().post()
                .accept(MediaType.TEXT_EVENT_STREAM)
                .body(BodyInserters.fromValue(param))
                .retrieve()
                .bodyToFlux(String.class)
                .flatMap(key -> makeUpResultParam(key, sessionId, sb))
                .onErrorResume(WebClientResponseException.class, ex -> {
                    logger.error("WebClient请求错误: {} - {}", ex.getStatusCode(), ex.getMessage());
                    return Flux.just(ex.getResponseBodyAsString());
                });
    }

    private Flux<String> makeUpResultParam(String key, String sessionId, StringBuffer sb) {
        logger.info("====={}", key);
        return Flux.just("process:"+key);

    }

日志一直没有,我这个是用websocket调用该方法的时候触发的,我在想,难道webFlux是只有springboot框架的web才支持的吗?于是我写了一个main方法做了一下测试

    public static void main(String[] args) throws InterruptedException {
        ChatService chatService = new ChatService();
        WebClient webClient = chatService.webClient();
        webClient.post()
                .accept(MediaType.TEXT_EVENT_STREAM)
                .body(BodyInserters.fromValue("{\"model\":\"deepseek-chat\",\"messages\":[{\"role\":\"system\",\"content\":\"你是一名人工助手,需以纯文本形式回答问题,禁止使用 Markdown 语法和换行符。\"},{\"role\":\"user\",\"content\":\"你好\"}],\"stream\":true}"))
                .retrieve()
                .bodyToFlux(String.class)
                .subscribe(
                        data -> System.out.println("Received: " + data),
                        err -> System.err.println("Error: " + err),
                        () -> System.out.println("Stream completed")
                );

    }

日志还是为空,什么也没有,我后来猜测deepseek的接口坏了之类的。。。

很显然不是的,最后我灵光一闪找到了问题,其实很简单的原因(看到这儿能一下看出问题的,绝对是基本功很扎实的高手)

揭晓答案:因为我用的main方法是主线程,Flux说到底是个异步方法,主线程不会等待没有阻塞的异步方法执行完才销毁的,那么知道原因后就可以修改代码了,最简单的方法加一个 CountDownLatch,这里不懂CountDownLatch的可以看这一个文章[juc辅助类]

    public static void main(String[] args) throws InterruptedException {
        ChatService chatService = new ChatService();
        WebClient webClient = chatService.webClient();
        //定义一个多线程计数器
        CountDownLatch countDownLatch = new CountDownLatch(1);

        webClient.post()
                .accept(MediaType.TEXT_EVENT_STREAM)
                .body(BodyInserters.fromValue("{\"model\":\"deepseek-chat\",\"messages\":[{\"role\":\"system\",\"content\":\"你是一名人工助手,需以纯文本形式回答问题,禁止使用 Markdown 语法和换行符。\"},{\"role\":\"user\",\"content\":\"你好\"}],\"stream\":true}"))
                .retrieve()
                .bodyToFlux(String.class)
                //线程结束了释放
                .doOnTerminate(countDownLatch::countDown)
                .subscribe(
                        data -> System.out.println("Received: " + data),
                        err -> System.err.println("Error: " + err),
                        () -> System.out.println("Stream completed")
                );
        //等待线程结束
       countDownLatch.await();
    }

这样就可以打印日志了,原理就是主线程等待协程处理完释放锁后才结束

ps:基本功学习后,多练才能融会贯通


评论