簡體   English   中英

在不使用線程的情況下處理 EJB3 中的超時

[英]Handling a timeout in EJB3 without using threads

我有以下情況。 我有一份工作:

  • 可能在給定時間后超時,如果發生需要拋出異常
  • 如果沒有超時,將返回一個結果
  • 如果此作業返回結果,則必須盡快返回,因為性能是一個非常重要的問題。 因此,異步解決方案不再適用,自然地通過錘擊來捆綁系統也不是一種選擇。
  • 最后,系統必須符合 EJB 標准,因此不能選擇使用普通線程的 AFAIK,因為這是嚴格禁止的。

我們當前的解決方案使用一個線程,該線程會在存在一定時間后拋出異常而不會被外部進程中斷,但是由於這顯然違反了 EJB 標准,我們正在嘗試通過其他方式解決它。

有任何想法嗎?

編輯添加:自然,超時的作業也需要刪除(或中斷)。

編輯添加2:這個問題似乎沒有任何解決方案,因為檢測死鎖似乎幾乎不可能堅持純EJB3標准。 由於 Enno Shioji 下面的評論反映了這一點,我將他的建議設置為正確答案。

使用 Bean Managed Transaction,可以使用 UserTransaction 接口指定特定事務的超時時間。

使用 begin 方法修改與當前線程啟動的事務關聯的超時值。

void setTransactionTimeout(int seconds) throws SystemException
  • 事務將在指定秒后超時,並且可能不會進一步傳播。 如果異常沒有隱式拋出,則可以根據結果顯式拋出。
  • 將在指定時間內成功完成返回結果。
  • 可以將它與無狀態 session bean 一起使用,因此可能不會出現性能問題。
  • 它的 EJB 標准因此不會成為實施的問題。

通過一點點工作,它應該在給定的場景中工作正常。

編輯:也可以使用服務器特定的屬性來管理事務超時。

JBoss :可以在 class 或方法級別注釋@TransactionTimeout(100)應用。

Weblogic :在 weblogic-ejb-jar.xml 中指定參數

<transaction-descriptor>
     <trans-timeout-seconds>100</trans-timeout-seconds> 
</transaction-descriptor>

GlassFish :在 sun-ejb-jar.xml 中使用可選的cmt-timeout-in-seconds元素

這更像是一個澄清請求,但它太長了,不適合作為評論..

我不確定你現在是怎么做的,因為從你寫的內容來看,僅僅使用請求處理線程似乎是 go 的方式。 像這樣:

//Some webservice method (synchronous)
public Result process(Blah blah){
    try{
        return getResult(TimeUnit.SECONDS, 10);
    }catch(InterruptedException e){
        //No result within 10 seconds!
        throw new ServiceUnavailableException("blah");
    }
}

我不確定你為什么要創建線程。 如果您因為getResult方法根本沒有超時而被迫使用線程,那么您將遇到線程泄漏。 如果它在較長時間后超時,因此您想“快捷地”回復用戶,那將是我考慮使用線程的唯一情況,就像我想象的那樣使用它。 這可能會導致線程在負載下堆積,我會努力避免這種情況。

也許您可以發布一些代碼,讓我們知道您為什么要在服務中創建?

另外,您的客戶端界面是什么? 聽起來像是一個同步網絡服務之類的?


在這種情況下,如果我是你,我會使用HashedWheelTimer作為 singleton ......這個機制應該很好地滿足你的要求( 這里是一個實現)。 然而,不幸的是,這似乎與 EJB 規范中對線程的禁令和對 singleton 的禁令相沖突。 實際上,如果您這樣做,確實沒有問題。 例如,請參閱此討論 我們還在 EJB 應用程序中使用了 singleton 模式。 它使用了 JBoss。 但是,如果這不是一個可行的選擇,那么我可能會考慮通過定義新的 web 服務(並將其部署在 Web 容器或其他東西中)來隔離其自己的 JVM 中的處理,並從 EJB 應用程序調用該服務。 然而,這顯然會導致性能下降,現在您將擁有另一個全新的應用程序。

將進程及其超時線程插入帶有@WebService 注釋的 class 中,然后從 EJB 調用 WebService。

WAR 沒有 EJB 那樣的限制或遵循相同的契約,因此它們可以安全地運行線程。

是的,我認為這是一種“hack”,但它符合要求,並且是可移植的。

您可以使用 commonj WorkManager 創建線程。 WebSphereWeblogic在提出標准時內置了一些實現,但您也可以找到其他應用服務器的實現。

基本上,WorkManager 允許您在容器內創建托管線程,就像在常規 Java 中使用 Executor 一樣。 您唯一的其他選擇是使用 MDB,但這將是一個“更重”的解決方案。

由於我不知道你的實際平台,你必須自己用你的平台谷歌 commonj 8-)

這是一個非 IBM 或 Oracle 解決方案。

注意:這不是一個實際的標准,但它可以廣泛用於不同的平台,並且應該很好地適合您的目的。

對於 EJB,有一個“容器管理事務”的概念。 通過在 bean 或特定方法上指定 @TransactionAttribute,容器將在調用方法時創建事務。 如果代碼的執行時間超過事務閾值,容器會拋出異常。 如果調用在事務閾值以下完成,它將照常返回。 您可以在調用代碼中捕獲異常並適當地處理它。

For more on container managed transactions, check out: http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Transaction3.html and http://download.oracle.com/javaee/5/tutorial/ doc/bncij.html

您可以使用@TimeOut 就像是:

@Stateless
public class TimedBean {

  @Resource
  private TimerService timerService;

  static private AtomicInteger counter = new AtomicInteger(0);
  static private Map<Integer, AtomicBoolean> canIRunStore = new ...;

  public void doSomething() {
    Integer myId = counter.getAndIncrement();
    AtomicBoolean canIRun = new AtomicBoolean(true);
    canIRunStore.put(myId, canIRun);

    timerService.createTimer(1000, 0, myId);

    while (canIRun.get() /* && some other condition */) {
      // do my work ... untill timeout ... 
    }
  }

  @Timeout
  @PermitAll
  public void timeout(Timer timer) {
    Integer expiredId = (Integer) timer.getInfo();
    AtomicBoolean canHeRun = canIRunStore.get(expiredId);
    canIRunStore.remove(expiredId);
    canHeRun.set(false);
  }
}

暫無
暫無

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

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