Search code examples
javaspringasynchronousblocking

java spring async future block on timely manner


e.g. I looking to find a way to execute @Async method not absolutely asynchronously. For example I want to invoke @Asynctask that will block my process for a up to a maximum defined time if task still haven't completed.

@Async
public Future<ModelObject> doSomething() {
   //here we will block for a max allowed time if task still haven't been completed
}

So such code will be semi asynchronous but the blocking time can be controlled by developer.

P.S : of course I can achieve this by simply blocking calling thread for a limited time. but I look to achieve that within spring layer


Solution

  • In short, no, there is no way to configure Spring to do this.

    The @Async annotation is handled by the AsyncExecutionInterceptor which delegates the work to a AsyncTaskExecutor. You could, in theory, write your own implementation of the AsyncTaskExecutor but even then there would be no way to use the @Async annotation to pass the desired wait time to your executor. Even then, it's not clear to me what the caller's interface would look like since they'd still be getting a Future object back. You would probably also need to subclass the Future object as well. Basically, by the time you are finished, you will have written the entire feature again more or less from scratch.

    You could always wrap the returned Future object in your own WaitingFuture proxy which provides an alternate get implementation although even then you'd have no way of specifying the wait value on the callee side:

    WaitingFuture<ModelObject> future = new WaitingFuture<ModelObject>(service.doSomething());
    ModelObject result = future.get(3000); //Instead of throwing a timeout, this impl could just return null if 3 seconds pass with no answer
    if(result == null) {
        //Path A
    } else {
        //Path B
    }
    

    Or if you don't want to write your own class then just catch the TimeoutException.

    Future<ModelObject> future = doSomething();
    try {
        ModelObject result = future.get(3000,TimeUnit.MILLISECONDS);
        //Path B
    } catch (TimeoutException ex) {
        //Path A
    }