In latest versions of PlayFramework they started using CompletionStage as return type for controllers that will be used for async execution or in a nutshell if you return CompletionStage it is asynchronous execution...
Now when we know the work we submit to CF is a long running IO operation we need to pass a custom executor (otherwise it will be executed on FJP by default).
Each controller execution has a HTTP context which has in it all the request information also this context is necessary to have your EntityManagers if you use JPA...
If we just create custom ExecutorService and inject it in our controller to use in supplyAsync() we wont have all the context information.
Here is an example of some controller action returning CompletionStage
return supplyAsync(() -> {
doSomeWork();
}, executors.io); // this is a custom CachedThreadPool with daemon thread factory
}
and if we try to run something like this in doSomeWork()
Request request = request(); // getting request using Controller.request()
or use preinjected JPAAPI jpa field in controller
jpa.withTransaction(
() -> jpa.em() // we will get an exception here although we are wrapped in a transaction
...
);
exception like
No EntityManager bound to this thread. Try wrapping this call in JPAApi.withTransaction, or ensure that the HTTP context is setup on this thread.
As you can see the jpa code is wrapped in transaction but no context was found because this is a custome pure java threadpool.
What is the correct way to provide all the context information when using CompletableFuture and custom executor?
I also tried defining custom executors in application.conf and lookup them from actor system but i will end up having MessageDispatcher which although is backed by ExecutorService is not compatible with CompletableFuture (maybe i'm wrong? if so how to use it with CF?)
You can use play.libs.concurrent.HttpExecution.fromThread method:
An ExecutionContext that executes work on the given ExecutionContext. The current thread's context ClassLoader and Http.Context are captured when this method is called and preserved for all executed tasks.
So, the code would be something like:
java.util.concurrent.Executor executor = getExecutorFromSomewhere();
return supplyAsync(() -> {
doSomeWork();
}, play.libs.concurrent.HttpExecution.fromThread(executor));
Or, if you are using a scala.concurrent.ExecutionContext:
scala.concurrent.ExecutionContext ec = getExecutorContext();
return supplyAsync(() -> {
doSomeWork();
}, play.libs.concurrent.HttpExecution.fromThread(ec));
But I'm not entirely sure that will preserve the EntityManager for JPA.
Related
I am writing a service where I want to expose an endpoint which will call another service and if the service call is successful then I want to send back the result to UI/ calling app.
In parallel before sending back the response, I want to execute/submit a task which should run in background and my call should not be dependent on success or failure of this task.
Before returning the response i want to do the-
executorService.execute(object);
This should not be a blocking call..
Any suggestion
Spring Async methods is the way to go here as was suggested in comments.
Some caveats:
Async methods can have different return types, its true that they can return CompletableFuture but this is in case if you called them from some background process and would like to wait/check for their execution status or perhaps, execute something else when the future is ready. In your case it seems that you want "fire-and-forget" behavior. So you should use void return type for your #Async annotated method.
Make sure that you place #EnableAsync. Under that hood it works in a way that it wraps the bean that has #Async methods with some sort of proxy, so the proxy is actually injected into your service. So #EnableAsync turns on this proxy generation mechanism. You can verify that this is the case usually in the debugger and checking the actual type of the injected reference object.
Consider customizing the the task executor to make sure that you're running the async methods with executor that matches your needs. For example, you won't probably want that every invocation of async method would spawn a new thread (and there is an executor that behaves like this). You can read about various executors here for example
Update
Code-wise you should do something like this:
public class MyAsyncHandler {
#Async
public void doAsyncJob(...) {
...
}
}
#Service
public class MyService {
#Autowired // or autowired constructor
private MyAsyncHandler asyncHandler;
public Result doMyMainJob(params) {
dao.saveInDB();
// do other synchronous stuff
Result res = prepareResult();
asyncHandler.doAsyncJob(); // this returns immediately
return res;
}
}
We use multithreading and need the context of the calling thread in each sub-thread. We're using Spring 4.3.
For example:
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
CompletableFuture.supplyAsync(() -> {
...
try {
// take the security context from the caller
SecurityContextHolder.getContext().setAuthentication(authentication);
doOperations()
This approach works fine for the Security context. It's passed from the caller thread (rest endpoint) and passes it to each created completable future.
At a given Class in the call chain, I've following construct:
#Context
protected ProvisioningContext provisioningContext;
#Context
protected UriInfo uriInfo;
How do I pass all contexts correctly in the newly created thread?
Approaches like ThreadContext.getContext() are not working.
You can try to implement something similar to what I described here
Customize/Extend Spring's #Async support for shiro
That is:
Use Spring's #Async annotation to execute tasks in different threads
Implement a custom ThreadPoolTaskExecutor that associates the current context(s) with the to be executed task
Make spring use this task executor by implementing a AsyncConfigurer
If you want to use something like CompletableFuture.supplyAsync or local executor services, you will end up with a lot of duplicated code compared to approached outlined above - using a thread pool that is managed by spring.
Especially for something like the authentication context it is important to take care of removing the context from the thread as well. Otherwise the context might still be attached to the thread if it is recycled be the executor service to execute another task.
Within my spring boot app I made several database calls asynchronously like so:
public List<Results> doWork() {
List<Observable<Results>> observables = Lists.newArrayList();
observables.add(
Observable.fromCallable(() -> dbQueryMethod(param1)).subscribeOn(Schedulers.io()));
observables.add(
Observable.fromCallable(() -> dbQueryMethod(param2)).subscribeOn(Schedulers.io()));
return Observable.merge(observables)
.toList()
.toBlocking()
.single();
}
#Transactional(readOnly=true)
public List<Results> myServiceMethod() {
doWork();
}
Basically the issue is that despite marking my service layer method as transaction & read only set to true, it's not actually passing the ThreadLocal state to the new threads spawned off by RxJava, causing the connections go to my master db instance and not the read replica.
We are currently using configured ContextHandlers and a ContextAwareSchedulerHook in App.java, but what do I need to do so that the new threads created by RxJava will inherit whatever ThreadLocal state is needed to manage them within the defined transaction?
Mark your dbQueryMethod with #Transactional(readOnly=true) and make sure you invoke it via Spring autowired proxy (not directly from the same class). Then io thread shall start new transaction, which will be read only.
I am working on a project that works in two flavors with and without multi tenancy.
The project exposes a REST service which I would like to be asynchronous.
So my basic service looks like
#Component
#Path("/resouce")
#Consumes(MediaType.APPLICATION_JSON)
public class ResouceEndpoint {
#POST
#ManagedAsync
public void add(final Event event, #Suspended final AsyncResponse asyncResponse) {
resouce.insert (event);
asyncResponse.resume( Response.status(Response.Status.NO_CONTENT).build());
}
}
That works fine without multi tenancy and I get the benefits of the internal Jersey executor service for free. See #ManagedAsync
When I switch to multi tenancy I add a filter on the request that resolve the tenant id and place it on the thread local (in our case the HTTP thread).
When the processing chain hits the "add()" method above the current thread is the one provided by the Jersey executor service, so it does not include my tenant id.
I could think only on the following options to work around this issue.
Extend the ResouceEndpoint to MutliTenantResouceEndpoint and drop the #ManagedAsync
Using my own thread executor
public class MutliTenantResouceEndpoint extends ResouceEndpoint {
#POST
public void add(final Event event, #Suspended final AsyncResponse asyncResponse) {
final String tenantId = getTeantIdFromThreadLocal();
taskExecutor.submit(new Callable<Void>() {
#Override
public Void call() throws Exception {
setTeantIdToThreadLocal(tenantId);
browserEventsAnalyzer.insertEvent(event);
Response response = Response.status(Response.Status.NO_CONTENT).build();
asyncResponse.resume(response);
return null;
}
});
}
}
But this way I need to manage my own thread executor and it feel's like I am missing something here.
Any suggestion on a different approach?
Here are a handful of recommendations, in order.
For context, I've been using Jersey for 2 years, and faced this exact problem 18 months ago.
1. Stop using #ManagedAsync
If you have control over the http server that Jersey is running on, I would recommend you stop using #ManagedAsync.
Instead of setting up Jersey to return it's http handling thread immediately and offload real request work to a managed executor service thread, use something like Grizzly for your http server, and configure it to have a larger worker thread pool. This accomplishes the same thing, but pushes the async responsibility down a layer, below Jersey.
You'll run into many pain points over the course of a year if you use #ManagedAsync for any medium-to-large project. Here are some of them off the top of my head:
If any ContainerRequestFilter's hits an external service (e.g. an auth filter hits your security module, which hits the database) you will lose the benefits you thought you were gaining
If your DB chokes and that auth filter call takes 5 seconds, Jersey hasn't offloaded work to the async thread yet, so your main thread needed to receive a new conn is blocked
If you set up logback's MDC in a filter, and you want that context throughout your request, you'll need to set up the MDC again on the managed async thread
Resource methods are cryptic to new comers and ugly to read because:
they need an extra parameter
they return void, hiding their real response type
they can "return" anywhere, without any actual return statements
Swagger or other API doc tools cannot automatically document async resource endpoints
Guice or other DI frameworks may have trouble dealing with certain scope bindings and/or providers in async resource endpoints
2. Use #Context and ContainerRequest properties
This would involve involved calling requestContext.setProperty("tenant_id", tenantId) in your filter, then calling calling requestContext.getProperty("tenant_id") in your resource with a #Context injected request.
3. Use HK2 AOP instead of Jersey filters
This would involve setting up an HK2 binding of InterceptionService which has a MethodInterceptor that checks for managed async resource methods and manually executes all RequestScoped bound ContainerRequestFilters. Instead of your filters being registered with Jersey, you'd register them with HK2, to be run by the method interceptor.
I can add more detail and code samples to options 2/3 if you'd like, or give additional suggestions, but it would first be helpful to see more of your filter code, and I again suggest option 1 if possible.
I looked through the documentation but couldn't find if there is a way to specify a timeout for async operations spawned when using #Async annotated methods using Spring 3.0.
Is there a way to do that? I think this is pretty essential whenever making triggering an async computation.
Timeouts are not provided by the #Async annotation, since the timeout should be decided by the caller of the function, not the function itself.
I'm assuming you're referring to the timeout on an #Async-annotated method which returns a result. Such methods should return an instance of Future, and the get() method on Future is used to specify the timeout.
e.g.
#Async
public Future<String> doSomething() {
return new AsyncResult<String>("test");
}
and then
Future<String> futureResult = obj.doSomething(); // spring makes this an async call
String result = futureResult.get(1, TimeUnit.SECOND);
In #Async source code is no option for configuration.