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;
}
为的DocumentsStoreBridge
TypedActor
的general
方法的实现如下:
@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错误。
任何帮助,这是非常感谢。
我不知道很多关于Spring MVC新版本4.1打包,但作为一个胡乱猜测,是它在内部使用ThreadLocals? – 2014-08-27 13:14:24
不是我所知道的。 AFIK将REST端点公开给调度程序servlet的Spring MVC层将使用HTTP线程池,然后我的代码将DeferredResult交给Akka actor,该角色被定义为使用默认配置,这是一个fork-join执行程序。我没有对如何使用线程做任何特定的配置更改,这可能本身就是问题,目前我只能不确定为什么这种行为会是间歇性的。 – nickebbitt 2014-08-27 14:34:57
我想知道如果这个问题的答案是相关的:http://stackoverflow.com/questions/24258951/jee6-long-polling-webservlet-exception-after-calling-asynccontextcomplete – nickebbitt 2014-08-28 08:41:22