Event driven to continue request thread execution in Spring MVC

Viewed 897

There is a method foo() in controller, which have to wait another method bar() triggered to continue execution.

    @GetMapping("/foo")
    public void foo(){
        doSomething();
        // wait until method bar() triggered
        doAnotherSomething();
    }   

    @GetMapping("/bar")
    public void bar(){
        // make foo() continue execute after being called
    }  

My solution is: saving a status flag in database/cache, while foo() is waiting, the thread loops searching if the status changed. However, this solution will blocke request thread for seconds. Is there any way to make foo() method run asynchronously, thus won't block thread execution?

2 Answers

This question is too broad. Yes you can use DeferredResult to finish a web request later. But doAnotherSomething() should actually do stuff asynchronously, otherwise you still end up using a thread, just not the one from the app server's pool. Which would be a waste since you can simply increase the app server's pool size and be done with it. "Offloading" work from it to another pool is a wild goose chase.

You achieve truly asynchronous execution when you wait on more than one action in a single thread. For example by using asynchronous file or socket channels you can read from multiple files/sockets at once. If you're using a database, the database driver must support asynchronous execution.

Here's an example of how to use the mongodb async driver:

@GetMapping("/foo")
public DeferredResult<ResponseEntity<?>> foo() {
    DeferredResult<ResponseEntity<?>> res = new DeferredResult<>();
    doSomething();
    doAnotherSomething(res);
    return res;
}

void doAnotherSomething(DeferredResult<ResponseEntity<?>> res) {
    collection.find().first(new SingleResultCallback<Document>() {
        public void onResult(final Document document, final Throwable t) {
            // process (document)
            res.setResult(ResponseEntity.ok("OK")); // finish the request
        }
    });
}

You can use CountDownLatch to wait till the dependent method is executed. For the sake of simplicity, I have used a static property. Make sure both methods have access to the same CountDownLatch object. ThreadLocal<CountDownLatch> could also be considered for this usecase.

private static CountDownLatch latch = new CountDownLatch(1);

@GetMapping("/foo")
public void foo(){
    doSomething();
    // wait until method bar() triggered
    latch.await();
    doAnotherSomething();
}   

@GetMapping("/bar")
public void bar(){
    // make foo() continue execute after being called
    latch.countDown();
} 
Related