2016-09-18 5 views
0

私はSpring Boot Webアプリケーションで長時間実行しています。 これは、それがどのように動作するかです:未来をHTTPリクエスト間で利用できる安全な方法は何ですか?

  • ユーザーがボタンをクリックすると、POST要求が行われ、運転が開始されます。
  • 操作に時間がかかるため、非同期で開始され、すぐに応答が送信されます。
  • JavaScriptを使用して、私は定期的にGETリクエストを送信して、操作が完了したかどうかを調べます。ここ

要求ハンドラである:

import java.util.concurrent.Future; 

@RequestMapping(value = "/start", method = RequestMethod.POST) 
@ResponseBody 
String start(HttpSession session) { 
    Future<String> result = resultService.result(); 
    session.setAttribute("result", result); 
    return "started"; 
} 

@RequestMapping(value = "/status") 
@ResponseBody 
String status(HttpSession session) throws Exception { 
    @SuppressWarnings("unchecked") 
    Future<String> result = (Future<String>) session.getAttribute("result"); 
    if (result != null && result.isDone()) { 
     return result.get(); 
    } else { 
     return "working"; 
    } 
} 

これは(別豆で)実行時間の長い操作である:

import org.springframework.scheduling.annotation.Async; 
import org.springframework.scheduling.annotation.AsyncResult; 

@Async 
@Override 
public Future<String> result() { 
    String result = computeResult(); // takes long 
    return new AsyncResult<String>(result); 
} 

完全な例はon GitHubあります。 また、それはどのように動作するかを示すa GIFです。今

、これは動作しますが、問題はSonarQubeが問題を提起したということです。

を「未来」とそのパラメータがシリアライズ可能またはセッションに保管しないでください。

これは、サーバーが「不動態化」と呼ばれるプロセスで、メモリ使用量を管理して

セッションは[...]、とにかくディスクに書き込むことができると説明しました。さらに、一部のサーバは、シャットダウン時にアクティブなセッションを自動的にファイルに書き出します。&は、起動時にそのようなセッションを非直列化します。

は、参照してくださいMITRE, CWE-579 - J2EEバッドプラクティス:私は要求間の長時間実行操作を追跡するためのより良い方法であるもの、Futureはシリアライズすることはできませんので、セッション

に保存されている非直列化可能なオブジェクト?

+0

この操作を起動時に「デシリアライズ」するか、再開しますか?そうであれば、操作の状態を保存してセッションに保存する方法を考えなければなりません。おそらくその状態クラスにFutureを実装する必要があります。そうでなければ、セッションに新しいクラスを格納するだけです。これは一時的なFutureフィールドを含んでいます。私はSpringMVCに精通していないので、これを行うより良い方法があれば驚くことはありません。 –

+0

私のソリューションは、私が今アクセスできない、DeferredResultとListenableFutureを使用しています。これらのキーワードを使用して私が使ったチュートリアルを見つけることができるかもしれません。 – Tim

答えて

1

、これは動作しますが、問題はSonarQubeが問題を提起していることである:

を上記の問題を解決するには、あなたが一緒にFutureオブジェクトの結果が含まれているSerializableを実装するラッパークラスを書くことができますFutureオブジェクトを一時的なものとして扱います。そして、Futureオブジェクトを直接置くのではなく、このセッションにwrapperオブジェクトを置くことができます。

例:これはちょうどあなたがSonarQubeに関して提起した問題を解決することを

public class ResultWrapper implements Serializable { 
    private String result = "working"; //String, since the resultService.result() is returning Future<String> 
    private transient Future future; //transient as it is not serializable. 

    public String getResult() { 
     if (future != null && future.isDone()) { 
      result = future.get(); 
      //Once the future is done, call the session.setAttribute(...) so that value of result field is replicated across the JVM nodes. 
     } 
     return result; 
    } 
} 

は注意してください。しかし、セッションレプリケーションがアクティブであっても、failoverまたはhandles activation/passivationは実際には提供されません。

webappがセッションレプリケーションを実行しているMM2の2つのノードがある場合、非同期ジョブcomputeResult();は明らかに1台のマシン(最初のリクエストを受信したマシン)でのみ実行されます。マシンがダウンすると、すべてのリクエストが他のアクティブなマシンに転送され、結果は常に「動作中」に戻ります。

webappでも1つのノードで実行されている別の問題は、セッションが不活性化されるとfutureは一時的であるためパッシベーションされないため、そのオブジェクトへの参照が緩くなり、 objをnullにします。最後に結果は上記の場合と同じです。

関連する問題