如何 运行 在另一个线程上阻塞代码并立即发出 http 请求 return
How to run blocking codes on another thread and make http request return immediately
我们用 Quarkus
和 Mutiny
开始了一个新项目,并用 Quarkus @Funq
创建了一堆端点,到目前为止一切正常。现在我们想在其中一个端点中处理一些非常耗时的事情,而我们期望的是,一旦用户单击按钮从前端发送 http 请求并点击该特定端点,我们将 return 202 Accepted
立即,将耗时的操作处理留在后端的另一个线程中,然后在完成后相应地发送通知邮件给用户。
我知道这可以用 @Async
或 CompletableFuture
来完成,但现在我们想用 Mutiny
来完成。根据我在这里阅读 Mutiny
文档的方式 https://smallrye.io/smallrye-mutiny/guides/imperative-to-reactive,runSubscriptionOn
将通过 运行 在另一个线程上使用耗时的方法来避免阻塞调用者线程,我的测试表明耗时的代码确实在不同的线程上执行。但是,http 请求会立即执行 not
return,直到耗时的方法完成执行(正如我在浏览器的开发人员工具中观察到的那样),它仍然处于等待状态。我是否误解了 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);
}
编辑:我根据@Ladicek 的回答找到了使用Uni
的解决方案。在深入研究 Quarkus 和 Uni 之后,我有一个后续问题:
目前我们的大多数阻塞方法都是 not
returning Uni 在 Service
级别,而不是我们从它们 return 的内容创建 Uni 对象(即对象或列表), 和 return Uni on Controller
level in their endpoints like this
return Uni.createFrom().item(() -> myService.myIOBlockingMethod(request))
.
正如@Ladicek 所解释的那样,我不必显式使用 .runSubscriptionOn
,因为 IO 阻塞方法会在工作线程上自动 运行(因为我在服务级别的方法 not
return大学)。这有什么缺点吗?我的理解是,这会导致更长的响应时间,因为它必须在 I/O 线程和工作线程之间跳转,对吗?
这方面的最佳做法是什么?对于 Service
级别上的那些阻塞方法,我是否应该始终 return Uni
以便它们也可以 运行 在 I/O 线程上?如果是这样,我想我总是需要在不同的工作线程上调用 .runSubscriptionOn
到 运行 它,这样 I/O 线程就不会被阻塞,对吗?
通过 returning a Uni
,您基本上是在说 Uni
完成时响应完成。您想要的是 运行 线程池上的操作和 return 完整的响应(Uni
与否,这无关紧要)。
顺便说一下,您在方法中为每个请求创建了一个额外的线程池,并且不要关闭它。那是错误的。您希望为所有请求创建一个线程池(例如,在 @PostConstruct
方法中)并且理想情况下在应用程序结束时也将其关闭(在 @PreDestroy
方法中)。
我们用 Quarkus
和 Mutiny
开始了一个新项目,并用 Quarkus @Funq
创建了一堆端点,到目前为止一切正常。现在我们想在其中一个端点中处理一些非常耗时的事情,而我们期望的是,一旦用户单击按钮从前端发送 http 请求并点击该特定端点,我们将 return 202 Accepted
立即,将耗时的操作处理留在后端的另一个线程中,然后在完成后相应地发送通知邮件给用户。
我知道这可以用 @Async
或 CompletableFuture
来完成,但现在我们想用 Mutiny
来完成。根据我在这里阅读 Mutiny
文档的方式 https://smallrye.io/smallrye-mutiny/guides/imperative-to-reactive,runSubscriptionOn
将通过 运行 在另一个线程上使用耗时的方法来避免阻塞调用者线程,我的测试表明耗时的代码确实在不同的线程上执行。但是,http 请求会立即执行 not
return,直到耗时的方法完成执行(正如我在浏览器的开发人员工具中观察到的那样),它仍然处于等待状态。我是否误解了 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);
}
编辑:我根据@Ladicek 的回答找到了使用Uni
的解决方案。在深入研究 Quarkus 和 Uni 之后,我有一个后续问题:
目前我们的大多数阻塞方法都是 not
returning Uni 在 Service
级别,而不是我们从它们 return 的内容创建 Uni 对象(即对象或列表), 和 return Uni on Controller
level in their endpoints like this
return Uni.createFrom().item(() -> myService.myIOBlockingMethod(request))
.
正如@Ladicek 所解释的那样,我不必显式使用 .runSubscriptionOn
,因为 IO 阻塞方法会在工作线程上自动 运行(因为我在服务级别的方法 not
return大学)。这有什么缺点吗?我的理解是,这会导致更长的响应时间,因为它必须在 I/O 线程和工作线程之间跳转,对吗?
这方面的最佳做法是什么?对于 Service
级别上的那些阻塞方法,我是否应该始终 return Uni
以便它们也可以 运行 在 I/O 线程上?如果是这样,我想我总是需要在不同的工作线程上调用 .runSubscriptionOn
到 运行 它,这样 I/O 线程就不会被阻塞,对吗?
通过 returning a Uni
,您基本上是在说 Uni
完成时响应完成。您想要的是 运行 线程池上的操作和 return 完整的响应(Uni
与否,这无关紧要)。
顺便说一下,您在方法中为每个请求创建了一个额外的线程池,并且不要关闭它。那是错误的。您希望为所有请求创建一个线程池(例如,在 @PostConstruct
方法中)并且理想情况下在应用程序结束时也将其关闭(在 @PreDestroy
方法中)。