Quarkus
我们用and开始了一个新项目,并Mutiny
用 Quarkus 创建了一堆端点,到目前为止@Funq
一切正常。现在我们想在其中一个端点处理一些非常耗时的事情,我们期望的是,一旦用户点击一个按钮从前端发送 http 请求并点击这个特定的端点,我们将202 Accepted
立即返回,留下从后端在另一个线程中进行耗时的操作处理,然后在完成后向用户发送相应的通知电子邮件。
我知道这可以用@Async
or来完成CompletableFuture
,但现在我们想用Mutiny
. 根据我Mutiny
在这里阅读文档的方式https://smallrye.io/smallrye-mutiny/guides/imperative-to-reactive,runSubscriptionOn
将通过在另一个线程上运行耗时的方法来避免阻塞调用者线程,并且我的测试显示了时间- 消耗代码确实在不同的线程上执行。但是,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 线程就不会被阻塞,对吗?