package com.tutego.ch_09.async;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.WebAsyncTask;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
@RestController
public class AsyncController {
private static final Logger logger = LoggerFactory.getLogger(AsyncController.class);
// by default, Spring uses SimpleAsyncTaskExecutor, which creates a new thread per task
@RequestMapping("/callable")
public Callable<String> callable() {
return () -> {
logger.info("{}", Thread.currentThread());
TimeUnit.SECONDS.sleep(10);
return "done";
};
}
@RequestMapping("/web-task-async")
public WebAsyncTask<String> webAsyncTask() {
return new WebAsyncTask<>(
5_000L, /* can define a timeout */
"can pass the executor name explicitly here",
() -> {
logger.info("{}", Thread.currentThread());
TimeUnit.SECONDS.sleep(10);
return "done";
}
);
}
@RequestMapping("/deferred-async")
public DeferredResult<String> deferredResultAsync() {
// similar to IO.async_ in Scala
var deferredResult = new DeferredResult<String>(5000L);
new Thread(() -> {
logger.info("{}", Thread.currentThread());
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
deferredResult.setResult("done");
}).start();
return deferredResult;
}
@RequestMapping("/streaming-response-body")
public ResponseEntity<?> streamingResponseBodyAsync() {
StreamingResponseBody streamingResponseBody = out -> {
out.write((byte) '[');
for (int i = 0; i < 100; i++) {
String line = "{\"index\": %d, \"value\": %d},%n";
byte[] bytes = line.formatted(i, ThreadLocalRandom.current().nextInt()).getBytes();
out.write(bytes);
out.flush();
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException ignored) {
}
}
out.write((byte) ']');
};
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=random.json")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(streamingResponseBody);
}
}