1

I have implemented a simple Rest service by which I'd like to test deferredResult from Spring. While am I getting texts in that order:

  1. TEST
  2. TEST 1
  3. TEST AFTER DEFERRED RESULT

I am very interested why in a browser (client) I need to wait that 8 seconds. Isn't that deferedResult shouldn't be non-blocking and run a task in the background? If no, how to create a rest service which will be non-blocking and run tasks in the background without using Java 9 and reactive streams?

@RestController("/")
public class Controller {

    @GetMapping
    public DeferredResult<Person> test() {
        System.out.println("TEST");
        DeferredResult<Person> result = new DeferredResult<>();
        CompletableFuture.supplyAsync(this::test1)
                .whenCompleteAsync((res, throwable) -> {
                    System.out.println("TEST AFTER DEFERRED RESULT");
                    result.setResult(res);
                });
        System.out.println("TEST 1");
        return result;
    }

    private Person test1() {
        try {
            Thread.sleep(8000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return new Person("michal", 20);
    }
}

class Person implements Serializable {
    private String name;
    private int age;
}
Bogdan Oros
  • 1,249
  • 9
  • 13
Jan Testowy
  • 649
  • 3
  • 13
  • 32

1 Answers1

1

DeferredResult is a holder for a WebRequest to allow the serving thread to release and serve another incoming HTTP request instead of waiting for the current one's result. After setResult or setError methods will be invoked - Spring will release that stored WebRequest and your client will receive the response.

DeferredResult holder is a Spring Framework abstraction for Non-blocking IO threading. Deferred result abstraction has nothing with background tasks. Calling it without threading abstractions will cause the expected same thread execution. Your test1 method is running in the background because of CompletableFuture.supplyAsync method invocation that gives the execution to common pool.

The result is returned in 8 seconds because the whenCompleteAsync passed callback will be called only after test1 method will return.

You cannot receive the result immediately when your "service call logic" takes 8 seconds despite you are performing it in the background. If you want to release the HTTP request - just return an available proper object (it could contain a UUID, for example, to fetch the created person later) or nothing from the controller method. You can try to GET your created user after N seconds. There are specific HTTP response codes (202 ACCEPTED), that means the serverside is processing the request. Finally just GET your created object.

The second approach (if you should notify your clientside - but I will not recommend you to do it if this is the only reason) - you can use WebSockets to notify the clientside and message with it.

Bogdan Oros
  • 1,249
  • 9
  • 13
  • Thanks for the response. So what are others way to accomplish to run task in the background- so in that case means that client will return value immediately and ex test1 method will continue running? – Jan Testowy Aug 22 '18 at 18:39
  • I updated the answer, but Reactive Programming will not help you in this case. The TCP connection should be open despite the used stack with HTTP. – Bogdan Oros Aug 22 '18 at 18:46
  • Thanks. So can you tell me what is the main difference between deferred result and @async annotation in spring? – Jan Testowy Aug 22 '18 at 18:53
  • `@Async` annotations just provide a declarative way to specify methods we as developers want to run in the background (another TreadPoolExecutor). It makes your methods run in the background instead of the `DeferredResult`. DeferredResult was implemented to make the threading IO more non-blocking (to allow one thread serve multiple requests) and is more coupled with MVC. Here is also a good explanation of the difference https://stackoverflow.com/questions/17855852/difference-between-spring-mvcs-async-deferredresult-and-callable – Bogdan Oros Aug 22 '18 at 18:57