То, что мне удалось сделать, но я не знаю, есть ли какие-то концептуальные или практические недостатки, это то, что следует ...
Во-первых, конфигурация пружинно-асинхронная
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
pool.setCorePoolSize(10);
pool.setMaxPoolSize(10);
pool.setWaitForTasksToCompleteOnShutdown(true);
return pool;
}
@Override
public Executor getAsyncExecutor() {
return new SimpleAsyncTaskExecutor();
}
}
И далее, модификации контроллера и сервиса:
@RestController
@RequestMapping("/timeout")
public class TestController {
@Autowired
private TestService service;
@GetMapping("/max10secs")
public String max10secs() throws InterruptedException, ExecutionException {
Future<String> futureResponse = service.call();
try {
//gives 10 seconds to finish the methods execution
return futureResponse.get(10, TimeUnit.SECONDS);
} catch (TimeoutException te) {
//in case it takes longer we cancel the request and check if the method is not done
if (futureResponse.cancel(true) || !futureResponse.isDone())
throw new TestTimeoutException();
else {
return futureResponse.get();
}
}
}
}
@Service
public class TestService {
@Async("threadPoolTaskExecutor")
public Future<String> call() {
try{
//some business logic here
return new AsyncResult<>(response);
} catch (Exception e) {
//some cancel/rollback logic when the request is cancelled
return null;
}
}
}
И, наконец, сгенерировать исключение TestTimeoutException:
@ResponseStatus(value = HttpStatus.REQUEST_TIMEOUT, reason = "too much time")
public class TestTimeoutException extends RuntimeException{ }