DeferredResult with time consuming processing resu

2019-09-10 10:29发布

问题:

I have one class that extends DeferredResults and extends Runnable as shown below

public class EventDeferredObject<T> extends DeferredResult<Boolean> implements Runnable {
private Long customerId;

private String email;

@Override
public void run() {

    RestTemplate restTemplate=new RestTemplate();

    EmailMessageDTO emailMessageDTO=new EmailMessageDTO("dineshshe@gmail.com", "Hi There");

//Very long running call
    Boolean result=restTemplate.postForObject("http://localhost:9080/asycn/sendEmail", emailMessageDTO, Boolean.class);

    this.setResult(result);
}

//Constructor and getter and setters
}

Now I have controller that return the object of the above class,whenever new request comes to controller we check if that request is present in HashMap(That stores unprocessed request at that instance).If not present then we are creating object of EventDeferredObject class can store that in HashMap and call start() method on it.If this type request is already present then we will return that from HashMap.On completion on request we will delete that request from HashMap.

@RequestMapping(value="/sendVerificationDetails")

public class SendVerificationDetailsController {

private ConcurrentMap<String , EventDeferredObject<Boolean>> requestMap=new  ConcurrentHashMap<String , EventDeferredObject<Boolean>>(); 
@RequestMapping(value="/sendEmail",method=RequestMethod.POST)
public EventDeferredObject<Boolean> sendEmail(@RequestBody EmailDTO emailDTO)
{
    EventDeferredObject<Boolean> eventDeferredObject = null;

    System.out.println("Size:"+requestMap.size());

    if(!requestMap.containsKey(emailDTO.getEmail()))
    {
        eventDeferredObject=new EventDeferredObject<Boolean>(emailDTO.getCustomerId(), emailDTO.getEmail());
        requestMap.put(emailDTO.getEmail(), eventDeferredObject);

        Thread t1=new Thread(eventDeferredObject);
        t1.start();

    }
    else
    {
        eventDeferredObject=requestMap.get(emailDTO.getEmail());

    }
    eventDeferredObject.onCompletion(new Runnable() {

        @Override
        public void run() {
            if(requestMap.containsKey(emailDTO.getEmail()))
            {   
                requestMap.remove(emailDTO.getEmail());
            }
        }
    });

    return eventDeferredObject;
}

}

Now as the processing of call in threads run() method takes 50000ms time so this results in exception as:

java.lang.IllegalStateException: Cannot forward after response has been committed
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:328)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:318)
    at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:433)
    at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:299)
    at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:393)
    at org.apache.catalina.core.AsyncContextImpl.setErrorState(AsyncContextImpl.java:434)
    at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:310)
    at org.apache.coyote.http11.AbstractHttp11Processor.asyncDispatch(AbstractHttp11Processor.java:1682)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:649)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

How to tackle this situation..if the processing time is around 20000ms code works fine.