我们开始了一个新项目Quarkus
and Mutiny
,并使用 Quarkus 创建了一堆端点@Funq
,到目前为止一切都运行良好。现在我们想要在一个端点中处理一些非常耗时的事情,我们期望的是,一旦用户单击按钮从前端发送 http 请求并点击这个特定端点,我们将返回202 Accepted
立即将耗时的操作处理留在后端的另一个线程中,然后在完成后向用户发送相应的通知电子邮件。
我知道这可以通过@Async
or CompletableFuture
,但现在我们想要这样做Mutiny
。根据我的阅读方式Mutiny
文档在这里https://smallrye.io/smallrye-mutiny/guides/imperative-to-reactive https://smallrye.io/smallrye-mutiny/guides/imperative-to-reactive, runSubscriptionOn
将通过在另一个线程上运行耗时的方法来避免阻塞调用者线程,并且我的测试显示耗时的代码确实在不同的线程上执行。但是,http 请求确实not
立即返回,它仍然处于挂起状态,直到耗时的方法完成执行(正如我在浏览器的开发人员工具中观察到的那样)。我是否误解了如何runSubscriptionOn
作品?我如何实现这个功能Mutiny
?
My @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);
}
Edit:我找到了解决方案Uni
基于@Ladicek 的回答。在深入研究 Quarkus 和 Uni 后,我有一个后续问题:
目前我们大部分的拦截方式是not
返回统一Service
level,相反,我们根据它们返回的内容(即对象或列表)创建 Uni 对象,并返回 UniController
像这样的端点级别
return Uni.createFrom().item(() -> myService.myIOBlockingMethod(request))
.
正如@Ladicek 所解释的,我不必使用.runSubscriptionOn
明确地,因为 IO 阻塞方法将自动在工作线程上运行(正如我在服务级别上的方法一样)not
返回大学)。这有什么缺点吗?我的理解是,这会导致更长的响应时间,因为它必须在 I/O 线程和工作线程之间跳转,我是否正确?
对此的最佳实践是什么?我应该总是回来吗Uni
对于那些阻止方法Service
级别以便它们也可以在 I/O 线程上运行?如果是这样,我想我总是需要打电话.runSubscriptionOn
在不同的工作线程上运行它,这样 I/O 线程就不会被阻塞,对吗?