Understanding AsyncController in Playframework example project - java

I am studying Playframework conceptions and what I have stuck with is AsyncController example that is stating the following description:
This controller contains an action that demonstrates how to write simple asynchronous code in a controller. It uses a timer to asynchronously delay sending a response for 1 second.
I'm marking the problematic statement in bold here.
Here is the code of controller where I removed the methods' descriptions not to waste space here on the question page.
#Singleton
public class AsyncController extends Controller {
private final ActorSystem actorSystem;
private final ExecutionContextExecutor exec;
#Inject
public AsyncControllerSO(ActorSystem actorSystem, ExecutionContextExecutor exec) {
this.actorSystem = actorSystem;
this.exec = exec;
}
public CompletionStage<Result> message() {
return getFutureMessage(1, TimeUnit.SECONDS).thenApplyAsync(Results::ok, exec);
}
private CompletionStage<String> getFutureMessage(long time, TimeUnit timeUnit) {
CompletableFuture<String> future = new CompletableFuture<>();
actorSystem.scheduler().scheduleOnce(
Duration.create(time, timeUnit),
() -> future.complete("Hi!"),
exec
);
return future;
}
}
I do not understand why the example giving the intuition of asynchrony in PlayFramework emphasises the "timer to asynchronously delay" feature?
As per the description of scheduleOnce method:
Schedules a Runnable to be run once with a delay, i.e. a time period that has to pass before the runnable is executed.
Doesn't the latter mean that the delay is being performing in the same thread as message() method runs and hence this cannot be considered as asynchrony?

Not getting into specifics of Akka or Play, the general idea about an asynchronous delay is that it doesn't block the thread, so something else can be done meanwhile. When you call .thenApplyAsync, you're setting a callback which will be executed on the result of the future when it's ready. So the scheduler knows what to do: schedule to run the future in 1 second, (if it has something else to do meanwhile, do it), once the future is ready, run the callback.

Related

Why Spring use ForkPoolJoin instead of ThreadPoolTaskExecutor with #Async?

For my studies, I'm working on a Spring Boot REST API. I'm supposed to reduce the execution time of the code when it received a request. So, I thought that make the code asynchronous would be a good idea. But, unfortunately, I face some problems with Spring for this, and despite the few hours of research online to find a solution, I didn't find anything. Let me explain :
To optimize my code, I decided to use #Async Spring Annotation. For this, I created an AsyncConfiguration class who looks like this :
#Configuration
#EnableAsync
public class AsyncConfiguration {
#Bean(name = "asyncExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
executor.setQueueCapacity(50);
executor.setThreadNamePrefix("AsynchThread-");
executor.initialize();
return executor;
}
}
Usually, the asyncExecutor() method returns the Executor class or sub-class that must be used by Spring for async calls. In this case, it's a ThreadPoolTaskExecutor. And the majority of my code is annotated with #Async to use my asyncExecutor, like this :
#Async("asyncExecutor")
public CompletableFuture<User> calculateRewards(User user) {
return CompletableFuture.supplyAsync(() -> {
logger.info("Calculating Reward for user : " + user.getUserName());
List<VisitedLocation> userLocations = user.getVisitedLocations();
List<Attraction> attractions = gps.getAllAttraction();
for(VisitedLocation visitedLocation : userLocations) {
for(Attraction attraction : attractions) {
if(user.getUserRewards().stream().filter(r -> r.attraction.attractionName.equals(attraction.attractionName)).count() == 0) {
if(nearAttraction(visitedLocation, attraction)) {
user.addUserReward(new UserReward(visitedLocation, attraction, reward.getAttractionRewardPoints(attraction.attractionId, user.getUserId())));
}
}
}
}
return user;
});
}
But, here's the point : when I run the code, Spring DON'T use my asyncExecutor() bean. How do I know that ? First, when I call an annotated method, in the terminal, here's what I see :
2022-10-27 00:26:24.688 INFO 41436 --- [onPool-worker-4] c.T.T.service.TourGuideMainService : Calculating Reward for user : internalUser919
The "[onPool-worker-4]" is the Thread name, or at least the end of the Thread name. But it's not supposed to be named like that. If you look at my asyncExecutor() method above, you can see that there is a executor.setThreadNamePrefix("AsynchThread-");. If the code was working as intended, the Thread should be called "AsynchThread-4", but It's not.
Secondly, I decided to run my code in Debug mode, and I went into the Debug menu of VS Code, and I dicovered two things :
1 - When I run my stress test who make 1000 calls of calculateRewards() simultaneously, there is only 11 Threads created. Considering the execution time of the calculateRewards() method AND the fact that the Executor have its maxPoolSize by default (i.e. Integer.MAX_VALUE), there should be more than 11 Threads ;
2 - The entire name of the Threads when they are created is "[ForkJoinPool.commonPool-worker-4]" ;
It seems that Spring is using the ForkJoinPool class to create Threads, and it don't ever consider the configuration of my Executor. I have no idea of why it's doing that, I never used ForkJoinPool at all, and like I said, I didn't find anything when searching about that online.
So, why Spring is using ForkJoinPool instead of ThreadPoolTaskExecutor for async methods in my code ? And most important : how can I address that ?
(I hope that it's understandable...)
EDIT 1 : During some random testing, I found that, if Spring seems to use some ForkJoinPool Threads to execute my code, it create a "AsynchThread" anyway but don't use it. That's even more confusing... -_-"
The problem here is that you are using CompletableFuture.supplyAsync to produce your CompletableFuture.
This method will fork off a task running in the ForkJoinPool.commonPool() and execute your Supplier in that task.
Since spring will supply the executor and run your entire method asynchronously, you shouldn't need to use the supplyAsync function with a lambda. Instead your async method should look something like this (inside of your service):
#Service
public class MyService {
...
#Async("asyncExecutor")
public CompletableFuture<User> calculateRewards(User user) {
logger.info("Calculating Reward for user : " + user.getUserName());
List<VisitedLocation> userLocations = user.getVisitedLocations();
List<Attraction> attractions = gps.getAllAttraction();
for(VisitedLocation visitedLocation : userLocations) {
for(Attraction attraction : attractions) {
if(user.getUserRewards().stream().filter(r -> r.attraction.attractionName.equals(attraction.attractionName)).count() == 0) {
if(nearAttraction(visitedLocation, attraction)) {
user.addUserReward(new UserReward(visitedLocation, attraction, reward.getAttractionRewardPoints(attraction.attractionId, user.getUserId())));
}
}
}
}
return CompletableFuture.completedFuture(user);
}
}
If you autowire your service into a CommandLineRunner that executes your method, you can use this runner to see that spring will handle executing your method asynchronously using the Executor you have defined in your configuration.
For example:
#Component
public class Runner implements CommandLineRunner {
private final MyService service;
public Runner(MyService service) {
this.service = service;
}
#Override
public void run(String... args) throws Exception {
CompletableFuture<User> user1 = service.calculateRewards(new User("user1"));
CompletableFuture<User> user2 = service.calculateRewards(new User("user2"));
CompletableFuture<User> user3 = service.calculateRewards(new User("user3"));
CompletableFuture.allOf(user1,user2,user3).join();
}
}

Why the CompletableFuture takes forever in my unit test?

I'm writing the unit tests for the old method, which uses CompletableFuture.supplyAsync(). The method is not complex, but my unit test keeps running and does not stop when executing the join(). I believe supplyAsync() should return the value very quickly. Is it because I set up the taskExecutor incorrectly? I'm new to Spring and Java, so please advise anything. Thank you.
Code:
public Response getReponse(Request request) {
CompletableFuture<String> vip = CompletableFuture.supplyAsync(() -> {
if(StringUtils.isBlank(request.getAddress())
){ return "";}
Request newRequest = Request.builder().
userId(request.getUserId()).
address(request.getZipCode()).
build();
Response newResult = getResult(newRequest);
return ("12345".equals(newResult.getZipCode()) + "";
}, taskExecutor);
final Response result = getResult(request);
result.setVIP(zipCode.join());
return result;
}
My unit test:
#Mock
private ThreadPoolTaskExecutor taskExecutor;
#Test
void getReponseTest(){
SomeService someService = new SomeService(Constants, logService, taskExecutor);
final SomeService someServiceSpy = Mockito.spy(someService);
final Request request = TestHelper.buildRequest();
final Response response = TestTestHelper.buildResponse();
doReturn(response).when(someServiceSpy).getResult(any(Request.class));
Response result = taxServiceSpy.getQuotationV2(taxRequest);
// assertion
...
}
You are mocking the ThreadPoolTaskExecutor so when it's told to execute the task, it is not doing anything. The CompletableFuture will never be completed, which is why things are hanging. You would need to either use a real ThreadPoolTaskExecutor, or implement the execute() method in the mocked Executor so it calls the run() method on the runnable passed to it. I don't understand what you're actually trying to accomplish in this unit test though. There doesn't seem to be a point to using an Executor at all. Also there is an error in the code since you call join on a variable called zipCode which does not exist, the future is called vip.
Like Jared mentioned, I built an executor, and it worked.
#Spy
private ThreadPoolTaskExecutor spyTaskExecutor = new ThreadPoolTaskExecutor();
spyTaskExecutor.setCorePoolSize(1);
spyTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
spyTaskExecutor.initialize();

Getting "No session currently bound to execution context" when using Threadpool Executor

I am new to Dropwizard and Hibernate.
Currently I am working on an application where I need to use AsyncThreadPool for performing some time consuming operations from my main thread which needs to send a response right away.
In the synchromous flow the operations are working fine because my listener has #UnitOfWork annotation in place. But in the threadpool spawned thread I am getting "No session currently bound to execution context" error every time.
I tried #UnitOfWork annotation on thread class as well as the run() method, as the documentation says that I have to use this annotation from the resource accessing the instance.
Here is my runnable class.
public class CallbackTask implements Runnable{
Snapshot baseSnapshot;
ProcessorResponse processorResponse;
Job job;
ElasticSearchDAO esDao;
OrchestratorJobService orchestratorJobService;
Snapshot snapshot;
RestoreHelper restoreHelper;
String indexName;
public CallbackTask(Snapshot baseSnapshot, ProcessorResponse processorResponse, Job job, ElasticSearchDAO esDao, OrchestratorJobService orchestratorJobService, Snapshot snapshot, RestoreHelper restoreHelper, String indexName) {
this.baseSnapshot = baseSnapshot;
this.processorResponse = processorResponse;
this.job = job;
this.esDao = esDao;
this.orchestratorJobService = orchestratorJobService;
this.snapshot = snapshot;
this.restoreHelper = restoreHelper;
this.indexName = indexName;
}
#Override
#Transactional
public void run() {
int retryCount = job.getRetrialCount()==null ? 0: job.getRetrialCount();
if(retryCount< JOB_RETRY_COUNT){
job.setRetrialCount(++retryCount);
//orchestratorJobService.runConfig(job.getConfigId(), null);
}else{
snapshot.setSoftDelete(true);
}
orchestratorJobService.persistData(job, snapshot);
}
Thanks in advance for any help.
Make sure that you're using a managed ExecutorService (i.e. do not create it yourself, use the built-in methods):
public class MyApplication extends Application<MyConfiguration> {
#Override
public void run(MyConfiguration configuration, Environment environment) {
ExecutorService executorService = environment.lifecycle()
.executorService(nameFormat)
.maxThreads(maxThreads)
.build();
ScheduledExecutorService scheduledExecutorService = environment.lifecycle()
.scheduledExecutorService(nameFormat)
.build();
}
}
#UnitOfWork uses the current session context strategy, so you need to put a session to the current thread context
Dropwizard #UnitOfWork with asynchronous database call

Mixing Java `ExecutorService` with Spring `TaskExecutor`

I have a piece of Java code that I previously used without Spring that looks like this:
// `Callable` instead of `Runnable` because we need to throw exceptions
public MyTask extends Callable<Void> {
#Override
public Void call() throws Exception { ... }
}
public class MyTasksRunner {
private final ExecutorService executorService;
...
public void run() throws Exception {
List<MyTask> tasks = ...;
var futures = executorService.invokeAll(tasks);
for (var future : futures) {
// Rethrow any exceptions happened in the threads.
future.get();
}
}
}
Now I'm merging this code into a larger Spring Boot application that has async enabled. It configures a TaskExecutor, which doesn't have the same interface as ExecutorService. A TaskExecutor can only run Runnables, not Callables.
I can probably have a TaskExecutor bean for async Spring, and another ExecutorService bean for the MyTasksRunner code at the same time. But I wonder what options I have if I want to merge those:
Can I tell Spring to use an ExecutorService for its async stuff?
Can I convert my Callable code to use Runnables instead, while still being able to propagate exceptions from the tasks?
I also thought about just making MyTask a Spring component and annotating it with #Async, but I don't really like that it makes the MyTask* code tied to Spring.
Yes, you can convert your Callable task to Runnable as I see you don't expect any return value. But with one condition - you cant throw Checked Exception however you may continue throwing Runtime Exception.
Also, yes you can define Executor bean as below to inject ExecutorService
#Bean
public Executor taskExecutor() {
ExecutorService executor = Executors.newFixedThreadPool(2);
return executor;
}
If you dont define an Executor bean, Spring creates SimpleAsyncTaskExecutor and uses that.

Multiple threads submit tasks and wait for results while another thread periodically executes each task

I have multiple threads that consume some data and call one third party service (serviceA). I can send only one request to serviceA per 10 second. Each thread have to wait until it receives a result from serviceA and then continue doing other thread specific work.
I want to implement some sort of proxy for serviceA that will receive all calls for serviceA, collect them, execute one call per 10 seconds and return a result of this call. Each thread should wait until the proxy returns the result. It should look something like this
public class ServiceAProxy implements ServiceA {
private ServiceA serviceA;
private ??? callsHolder;
public ServiceAProxy(ServiceA serviceA) {
this.serviceA = serviceA;
}
public Result call(String parameter) {
return callsHolder.submitAndWaitResult(() -> serviceA.call(parameter));
}
#Scheduled(fixedDelay = 10000)
public void executeOldestCall() {
callsHolder.executeOldestTask();
}
}
Probably callHolder could be implemented using 2 SynchronousQueues but is there any cleaner solution to do this without reinventing the wheel?
In case number of threads is small and blocking of a calling thread until it can send the request is not a big deal, Guava RateLimiter may be just enough. So your service proxy would look something like this:
public class ServiceAProxy implements ServiceA {
private final ServiceA serviceA;
private final RateLimiter throttle;
public ServiceAProxy(ServiceA serviceA, double callsPerSecond) {
this.serviceA = serviceA;
throttle = RateLimiter.create(callsPerSecond);
}
public Result call(String parameter) {
// every thread may potentially block here until throttle allows it to proceed
throttle.acquire();
return serviceA.call(parameter);
}
}

Categories

Resources