2014-08-27 69 views
0

我已經實現了各種Spring MVC REST端點來公開返回DeferredResult的服務,該服務被交給Akka TypedActor完成。該應用程序被部署到Glassfish 4服務器中。當DeferredResult傳遞給Akka actor時,Spring MVC異步請求會間歇性地超時

一般服務執行並返回的預期,但我間歇性地接收出現在我指定的超時間隔以下異常:

WARNING: Error invoking requestDestroyed method on ServletRequestListener org.jboss.weld.servlet.WeldListener 
java.lang.NullPointerException 
    at org.jboss.weld.context.AbstractBoundContext.deactivate(AbstractBoundContext.java:71) 
    at org.jboss.weld.context.http.HttpRequestContextImpl.deactivate(HttpRequestContextImpl.java:70) 
    at org.jboss.weld.servlet.WeldListener.requestDestroyed(WeldListener.java:154) 
    at org.apache.catalina.core.StandardContext.fireRequestDestroyedEvent(StandardContext.java:5261) 
    at org.apache.catalina.core.StandardHostValve.postInvoke(StandardHostValve.java:255) 
    at org.apache.catalina.connector.Request.errorDispatchAndComplete(Request.java:4484) 
    at org.apache.catalina.connector.Request.asyncTimeout(Request.java:4424) 
    at org.apache.catalina.connector.Request.processTimeout(Request.java:4458) 
    at org.apache.catalina.connector.Request.access$000(Request.java:156) 
    at org.apache.catalina.connector.Request$6.onTimeout(Request.java:4302) 
    at org.glassfish.grizzly.http.server.Response$SuspendTimeout.onTimeout(Response.java:2024) 
    at org.glassfish.grizzly.http.server.Response$DelayQueueWorker.doWork(Response.java:2073) 
    at org.glassfish.grizzly.http.server.Response$DelayQueueWorker.doWork(Response.java:2068) 
    at org.glassfish.grizzly.utils.DelayedExecutor$DelayedRunnable.run(DelayedExecutor.java:158) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    at java.lang.Thread.run(Thread.java:724) 

的servlet定義是我web.xml如下:

<servlet> 
    <servlet-name>DispatcherServlet</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <init-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value/> 
    </init-param> 
    <load-on-startup>1</load-on-startup> 
    <async-supported>true</async-supported> 
</servlet> 

我Spring MVC的一個端點的一個例子是:

@RequestMapping(value = "/general", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) 
@ResponseStatus(HttpStatus.ACCEPTED) 
public DeferredResult<String> processGeneralDocuments(@RequestBody DocumentsRequestBody requestBody) { 

    DeferredResult<String> result = new DeferredResult<>(appConfig.getDefaultRestTimeout()); 

    documentsServiceBridge.general(result, requestBody.getDocuments()); 

    return result; 

} 

爲的DocumentsStoreBridgeTypedActorgeneral方法的實現如下:

@Override 
public void general(DeferredResult<String> result, List<AbstractDocument> documents) { 
    LOG.debug("Processing {} general documents...", documents.size()); 

    try { 
     result.setResult(documents.size() + " general documents accepted."); 
     LOG.debug("DeferredResult set"); 
     for (AbstractDocument document : documents) { 
      documentStore.get().getActorRef().tell(document, TypedActor.context().self()); 
      LOG.debug("{} document sent to {}", document.get_id(), documentStore.get().getActorType()); 
     } 
    } catch (Exception e) { 
     result.setErrorResult(e); 
    } 

} 

正如你可以在DocumentsStoreBridge實現我幾乎立即設置DeferredResult的結果看,所以可以預料,完成異步請求。

實際上,間歇性地發生的情況是結果設置正確,程序的流程繼續進行,但異步請求未完成,因此客戶端在請求超時時收到HTTP 500錯誤。

任何幫助,這是非常感謝。

+0

我不知道很多關於Spring MVC新版本4.1打包,但作爲一個胡亂猜測,是它在內部使用ThreadLocals? – 2014-08-27 13:14:24

+0

不是我所知道的。 AFIK將REST端點公開給調度程序servlet的Spring MVC層將使用HTTP線程池,然後我的代碼將DeferredResult交給Akka actor,該角色被定義爲使用默認配置,這是一個fork-join執行程序。我沒有對如何使用線程做任何特定的配置更改,這可能本身就是問題,目前我只能不確定爲什麼這種行爲會是間歇性的。 – nickebbitt 2014-08-27 14:34:57

+1

我想知道如果這個問題的答案是相關的:http://stackoverflow.com/questions/24258951/jee6-long-polling-webservlet-exception-after-calling-asynccontextcomplete – nickebbitt 2014-08-28 08:41:22

回答

0

這個問題現在似乎已得到解決之後升級到GlassFish 4.1,我想WELD包含修復