簡體   English   中英

使用CompletableFutures和Java時的PlayFramework自定義執行程序

[英]PlayFramework custom executors when using CompletableFutures and java

在最新版本的PlayFramework中,他們開始使用CompletionStage作為將用於異步執行的控制器的返回類型,或者簡而言之,如果返回CompletionStage則是異步執行...

現在,當我們知道提交給CF的工作是長時間運行的IO操作時,我們需要傳遞一個自定義執行程序(否則它將默認在FJP上執行)。

每個控制器執行都有一個HTTP上下文,其中包含所有請求信息,如果使用JPA則此上下文對於擁有EntityManagers是必需的。

如果僅創建自定義ExecutorService並將其注入到控制器中以便在supplyAsync()使用,我們將不會獲得所有上下文信息。

這是一些返回CompletionStage控制器動作的示例

return supplyAsync(() -> {
   doSomeWork();
}, executors.io); // this is a custom CachedThreadPool with daemon thread factory

}

如果我們嘗試在doSomeWork()運行類似的doSomeWork()

Request request = request(); // getting request using Controller.request()

或在控制器中使用JPAAPI jpa字段

jpa.withTransaction(
    () -> jpa.em() // we will get an exception here although we are wrapped in a transaction
             ...
);

像這樣的異常

No EntityManager bound to this thread. Try wrapping this call in JPAApi.withTransaction, or ensure that the HTTP context is setup on this thread.

如您所見,jpa代碼包裝在事務中,但是未找到任何上下文,因為這是一個純定制Java線程池。

使用CompletableFuture和自定義執行程序時提供所有上下文信息的正確方法是什么?

我還嘗試在application.conf定義自定義執行application.conf ,並從actor系統中查找它們,但最終我將得到MessageDispatcher ,該MessageDispatcher雖然由ExecutorService支持,但與CompletableFuture不兼容(也許我錯了?如果這樣,如何在CF中使用它? )

您可以使用play.libs.concurrent.HttpExecution.fromThread方法:

一個ExecutionContext ,它在給定的ExecutionContext上執行工作。 當調用此方法並將其保留用於所有已執行任務時,將捕獲當前線程的上下文ClassLoaderHttp.Context

因此,代碼將類似於:

java.util.concurrent.Executor executor = getExecutorFromSomewhere();
return supplyAsync(() -> {
    doSomeWork();
}, play.libs.concurrent.HttpExecution.fromThread(executor));

或者,如果您使用的是scala.concurrent.ExecutionContext

scala.concurrent.ExecutionContext ec = getExecutorContext();
return supplyAsync(() -> {
    doSomeWork();
}, play.libs.concurrent.HttpExecution.fromThread(ec));

但是我不完全確定會保留用於JPA的EntityManager

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM