I have implemented various Spring MVC REST endpoints to expose services that return a DeferredResult
which is handed off to an Akka TypedActor
to be completed. The application is deployed into a Glassfish 4 server.
Generally the services execute and return as expected but I am intermittently receiving the following exception that occurs at the timeout interval I have specified:
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)
The servlet definition is my web.xml
is as follows:
<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>
An example of one of my Spring MVC endpoints is:
@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;
}
The implementation for the general
method of the DocumentsStoreBridge
TypedActor
is as follows:
@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);
}
}
As you can see in the DocumentsStoreBridge
implementation I am setting the result of the DeferredResult almost immediately, so would expect that to complete the asynchronous request.
What actually happens, intermittently, is that the result is set correctly, and the flow of my program continues, however the asynchronous request is not completed and therefore the client receives a HTTP 500 error when the request times out.
Any help with this is greatly appreciated.