2017-06-02 6 views
1

で非同期呼び出しを取り扱い、私はこのようになります@ManagedAsync方法のクラスで、リソースClassを持っている:cleanupDirtyDataへの呼び出しは、しばらく時間がかかることができるのでDropwizardでJAX-RS:即時応答

@Path("my-resource") 
public class MyResource extends BaseResource{ 

    private DatumDAO datumDAO; 

    public MyResource(DatumDAO datumDAO){ 
     this.datumDAO = datumDAO; 
    } 

    public void cleanDatum(Datum datum){ 
     //time taking operations 
    } 

    @GET 
    @ManagedAsync 
    @Path("/cleanup/{from}/{till}/") 
    @Consumes(MediaType.APPLICATION_JSON) 
    @Produces(MediaType.APPLICATION_JSON) 
    @UnitOfWork 
    public void cleanupDirtyData(@Suspended final AsyncResponse asyncResponse, @PathParam("from") DateTimeParam from, 
      @PathParam("till") DateTimeParam till) throws IOException{ 

     logger.debug("will try to cleanup dirty data in range: " + from + " " + till); 
     List<Datum> data = datumDAO.getALlDirtyDatumInRange(from.get().toDate(), till.get().toDate()); 
     Map<Long,String> cleanupMap = new HashMap<Long,String>(); 
     for(Datum datum: data){ 
      cleanDatum(datum); 
      cleanupMap.put(datum.getId(), "cleaned"); 
     } 
     // this response need to be sent [can be ignored]  
     asyncResponse.resume(Response.status(HttpStatus.OK_200).entity(cleanupMap).build()); 

    } 

} 

、私はドンクライアントが完全に待機するようにしたいのですが、実行作業は別のワーカースレッドに委ねられていることを理解しています。

私が達成しようとしているのは、クライアントに即座に応答し、機能cleanupDirtyDataを非同期的に実行し続けることです。

だから、次のことを試みた:

力強いタイムアウトを置くと、クライアントへの時期尚早な応答を与えるが、それは理想的な方法ではないようですし、それが実行を停止します。

@Path("my-resource") 
public class MyResource extends BaseResource{ 

    private DatumDAO datumDAO; 

    public MyResource(DatumDAO datumDAO){ 
     this.datumDAO = datumDAO; 
    } 

    public void cleanDatum(Datum datum){ 
     //time taking operations 
    } 

    @GET 
    @ManagedAsync 
    @Path("/cleanup/{from}/{till}/") 
    @Consumes(MediaType.APPLICATION_JSON) 
    @Produces(MediaType.APPLICATION_JSON) 
    @UnitOfWork 
    public void cleanupDirtyData(@Suspended final AsyncResponse asyncResponse, @PathParam("from") DateTimeParam from, 
      @PathParam("till") DateTimeParam till) throws IOException{ 

     // Register handler and set timeout 
     asyncResponse.setTimeoutHandler(new TimeoutHandler() { 
      public void handleTimeout(AsyncResponse ar) { 
       asyncResponse.resume(Response.status(SERVICE_UNAVAILABLE).entity(
        "Operation timed out -- please try again").build());      
       } 
     }); 
     ar.setTimeout(15, TimeUnit.SECONDS);  

     logger.debug("will try to cleanup dirty data in range: " + from + " " + till); 
     List<Datum> data = datumDAO.getALlDirtyDatumInRange(from.get().toDate(), till.get().toDate()); 
     Map<Long,String> cleanupMap = new HashMap<Long,String>(); 
     for(Datum datum: data){ 
      cleanDatum(datum); 
      cleanupMap.put(datum.getId(), "cleaned"); 
     } 
     // this response need to be sent [can be ignored]    
     asyncResponse.resume(Response.status(HttpStatus.OK_200).entity(cleanupMap).build()); 

    } 

} 
+1

_ "cleanupDirtyDataの呼び出しに時間がかかることがあるので、クライアントが完全に待つことを望ましくありません" - なぜそれが意味をなさないのか知りたいですか?あなたのコードでは、レスポンスボディをクライアントに返すためです。その応答本体が「長期実行」の一部である場合、本体を取得する実行が完了していないときに、どのようにクライアントに応答を返すことを期待しますか?私が間違っている場合は、コード内で長時間実行されている作業は何ですか? –

+0

@peeskilletプレースホルダコードだったので、ジョブが完了した後で応答を返す必要はありません。長時間実行されるタスクには、最大15分かかるディスクI/Oが多数必要です。 – anand

答えて

5

JAX-RS非同期サーバーAPIはすべてコンテナが要求をどのように管理するかについてです:次のようになります

。しかしそれは依然として依頼を保持し、クライアントの経験に影響を与えません。サーバ側の非同期処理モデルの使用は クライアントによって知覚要求処理時間を改善しないこと

注:Asynchronous Server APIについてのジャージー資料を引用

。ただし、 要求がまだキュー内で処理待ちになっている間に、 初期要求処理スレッドをI/Oコンテナに戻すことで、サーバーのスループットが向上するか、 の処理が別の専用糸。 リリースされたI/Oコンテナスレッドを使用して、新しい受信接続の を受け入れて処理することができます。あなたがクライアントに即座に応答を与えたい場合は

、あなたが何かを探していることがあります。

@Singleton 
@Path("expensive-task") 
public class ExpensiveTaskResource { 

    private ExecutorService executor; 

    private Future<String> futureResult; 

    @PostConstruct 
    public void onCreate() { 
     this.executor = Executors.newSingleThreadExecutor(); 
    } 

    @POST 
    public Response startTask() { 
     futureResult = executor.submit(new ExpensiveTask()); 
     return Response.status(Status.ACCEPTED).build(); 
    } 

    @GET 
    public Response getResult() throws ExecutionException, InterruptedException { 
     if (futureResult != null && futureResult.isDone()) { 
      return Response.status(Status.OK).entity(futureResult.get()).build(); 
     } else { 
      return Response.status(Status.FORBIDDEN).entity("Try later").build(); 
     } 
    } 

    @PreDestroy 
    public void onDestroy() { 
     this.executor.shutdownNow(); 
    } 
} 
public class ExpensiveTask implements Callable<String> { 

    @Override 
    public String call() throws Exception { 

     try { 
      Thread.sleep(10000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 

     return "Task completed"; 
    } 
} 

サーブレットコンテナで、あなたは高価なタスクを実行するためにExecutorServiceを使用することができます。 Java EEコンテナでは、ManagedExecutorServiceと考えるべきです。

+0

素敵な説明+1。 –