0

Quarkus我们用and开始了一个新项目,并Mutiny用 Quarkus 创建了一堆端点,到目前为止@Funq一切正常。现在我们想在其中一个端点处理一些非常耗时的事情,我们期望的是,一旦用户点击一个按钮从前端发送 http 请求并点击这个特定的端点,我们将202 Accepted立即返回,留下从后端在另一个线程中进行耗时的操作处理,然后在完成后向用户发送相应的通知电子邮件。

我知道这可以用@Asyncor来完成CompletableFuture,但现在我们想用Mutiny. 根据我Mutiny在这里阅读文档的方式https://smallrye.io/smallrye-mutiny/guides/imperative-to-reactiverunSubscriptionOn将通过在另一个线程上运行耗时的方法来避免阻塞调用者线程,并且我的测试显示了时间- 消耗代码确实在不同的线程上执行。但是,http 请求确实会not立即返回,它仍然处于挂起状态,直到耗时的方法完成执行(正如我在浏览器的开发人员工具中观察到的那样)。我误解了它的runSubscriptionOn工作原理吗?如何使用 实现此功能Mutiny

我的@Funq端点看起来像这样

@Inject
MyService myService;

@Funq("api/report")
public Uni<String> sendReport(MyRequest request) {
    ExecutorService executor = Executors.newFixedThreadPool(10, r -> new Thread(r, "CUSTOM_THREAD"));

    return Uni.createFrom()
        .item(() -> myService.timeConsumingMethod(request))
        .runSubscriptionOn(executor);
} 

编辑:我Uni根据@Ladicek 的回答找到了解决方案。在深入研究 Quarkus 和 Uni 之后,我有一个后续问题:

目前我们的大多数阻塞方法都是not在级别上返回 Uni Service,而不是我们从它们返回的内容(即对象或列表)中创建 Uni 对象,并Controller在其端点中返回 Uni 级别,如下所示

return Uni.createFrom().item(() -> myService.myIOBlockingMethod(request)).

正如@Ladicek 解释的那样,我不必.runSubscriptionOn显式使用,因为 IO 阻塞方法将自动在工作线程上运行(因为我在服务级别的方法确实not返回 Uni)。这有什么缺点吗?我的理解是,这将导致更长的响应时间,因为它必须在 I/O 线程和工作线程之间跳转,对吗?

对此的最佳做法是什么?我是否应该始终Uni在级别返回这些阻塞方法,Service以便它们也可以在 I/O 线程上运行?如果是这样,我想我总是需要调用.runSubscriptionOn以在不同的工作线程上运行它,这样 I/O 线程就不会被阻塞,对吗?

4

1 回答 1

1

通过返回 a Uni,您基本上是在说完成时响应已Uni完成。您想要的是在线程池上运行该操作并返回一个完整的响应(Uni与否,没关系)。

顺便说一句,您正在为每个请求在方法中创建一个额外的线程池,并且不要将其关闭。那是错误的。您想为所有请求(例如在一个@PostConstruct方法中)创建一个线程池,并且理想情况下在应用程序结束时(在一个方法中)也将其关闭@PreDestroy

于 2021-09-25T15:18:12.313 回答