Spring async method called from another async method - java

I'm using Spring 4 and I've noticed an odd behaviour... if I'm calling an async method multiple times from a normal instance method then they are all called in different threads and finish at random times. But if I call multiple times an async method from another async method then they finish in order. I have something like this:
#Async
public void nonAsyncMethod() {
for (int i = 0; i < 30; i++) {
asyncMethod();
}
}
#Async
public void asyncMethod() {
... something here
}
I'm using the default async executor. Should I use a different one? However this executor do not reuse any threads and starts another one every time so it should be fine... Can it be just a coincidence? But I've tried like more than 10 times and if I revert back to non-async for the first method then they finish randomly

What you are describing is a classic pitfall of Spring AOP.
In short, for Spring to be able to provide the async behavior it needs to create a proxy for your class at runtime. The proxy then does whatever it needs to do before and/or after calling your code. But in your case, the proxy mechanism is not being applied for the second method.
When a bean of your class is injected via Spring into some other component, Spring really injects the proxy instead. Therefor the relevant method of the proxy is called. However, when you are calling a method from inside the class, the limitations of Spring AOP mean the proxy never comes into play, but instead the regular method is called - with no extra features.
That is why asyncMethod is always executing on the same thread as the other method in the same class that called it.
Check out this excellent blog post as well as this part of Spring documentation.
There are some ways around the problem (check out this) that don't require you to refactor your code, but if you want async to work on both methods no matter what, the simplest thing to do is refactor the second method into another class.

Related

Spring 5.x - How to cleanup a ThreadLocal entry

Apologies for the long question..
I'm fairly new to Spring and don't understand the inner working fully yet.
So, my current java project has Spring 4.x code written way back in 2015 that uses ThreadLocal variable to store some user permission data.
The flow starts as a REST call in a REST controller which then calls the backend code and checks for user permissions from the DB.
There is a #Repository class that has a static instance of ThreadLocal where this user permission is stored. The ThreadLocal variable is updated by the calling thread.
So, if the thread finds data in the ThreadLocal instance already present for it, it just reads that data from the ThreadLocal variable and works away. If not, it goes to DB tables and fetches new permission data and also updates the ThreadLocal variable.
So my understanding is that ThreadLocal variable was used as these user permissions are needed multiple times within the same REST Call. So the idea was for a given REST request since the thread is the same, it needn't fetch user permissions from DB and instead can refer to its entry in the ThreadLocal variable within the same REST request.
Now, this seems to work fine in Spring 4.3.29.RELEASE as every REST call was being serviced by a different thread.(I printed Thread IDs to confirm.)
Spring 4.x ThreadStack up to Controller method call:
com.xxx.myRESTController.getDoc(MyRESTController.java),
org.springframework.web.context.request.async.WebAsyncManager$5.run(WebAsyncManager.java:332),
java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511),
java.util.concurrent.FutureTask.run(FutureTask.java:266),
java.lang.Thread.run(Thread.java:748)]
However, when I upgraded to Spring 5.2.15.RELEASE this breaks when calling different REST endpoints that try to fetch user permissions from the backend.
On printing the Stacktrace in the backend, I see there is a ThreadPoolExecutor being used in Spring 5.x.
Spring 5.x ThreadStack:
com.xxx.myRESTController.getDoc(MyRESTController.java),
org.springframework.web.context.request.async.WebAsyncManager.lambda$startCallableProcessing$4(WebAsyncManager.java:337),
java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511),
java.util.concurrent.FutureTask.run(FutureTask.java:266),
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149),
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624),
java.lang.Thread.run(Thread.java:748)]
So in Spring 5.x, it looks like the same thread is being put back in the ThreadPool and later gets called for multiple different REST calls.
When this thread looks up the ThreadLocal instance, it finds stale data stored by it for an earlier unrelated REST call. So quite a few of my test cases fail due to stale data permissions being read by it.
I read that calling ThreadLocal's remove() clears the calling thread's entry from the variable (which wasn't implemented at the time).
I wanted to do this in a generic way so that all REST calls call the remove() before the REST Response is sent back.
Now, in order to clear the ThreadLocal entry, I tried
writing an Interceptor by implementing HandlerInterceptor but this didn't work.
I also wrote another Interceptor extending HandlerInterceptorAdapter and calling ThreadLocal's remove() in its afterCompletion().
I then tried implementing ServletRequestListener and called the ThreadLocal's remove() from its requestDestroyed() method.
In addition, I implemented a Filter and called remove() in doFilter() method.
All these 4 implementations failed cos when I printed the Thread IDs in their methods they were the exact same as each other, but different to the Thread ID being printed in RestController method.
So, the Thread calling the REST endpoint is a different thread from those being called by the above 4 classes. So the remove() call in the above classes never clears anything from ThreadLocal variable.
Can someone please provide some pointers on how to clear the ThreadLocal entry for a given thread in a generic way in Spring?
As you noticed, both the HandlerInterceptor and the ServletRequestListener are executed in the original servlet container thread, where the request is received. Since you are doing asynchronous processing, you need a CallableProcessingInterceptor.
Its preProcess and postProcess methods are executed on the thread where asynchronous processing will take place.
Therefore you need something like this:
WebAsyncUtils.getAsyncManager(request)//
.registerCallableInterceptor("some_unique_key", new CallableProcessingInterceptor() {
#Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task,
Object concurrentResult) throws Exception {
// remove the ThreadLocal
}
});
in a method that has access to the ServletRequest and executes in the original servlet container thread, e.g. in a HandlerInterceptor#preHandle method.
Remark: Instead of registering your own ThreadLocal, you can use Spring's RequestAttributes. Use the static method:
RequestContextHolder.currentRequestAttributes()
to retrieve the current instance. Under the hood a ThreadLocal is used, but Spring takes care of setting it and removing it on every thread where the processing of your request takes place (asynchronous processing included).

Spring aspects across multiple threads

Trying to wrap service class with two aspects to get this call chain:
javanica..HystrixCommandAspect -> MyCustomAroundAspect -> MyService
met two problems:
HystrixCommandAspect does not call joinPoint.proceed(). Instead it calls method directly on target class, which effectively skips any other proxies created after javanica's aspect
Hystrix aspect makes subsequent calls running in deferent thread. It leads to message:
"No MethodInvocation found: Check that an AOP invocation is in progress, and that the ExposeInvocationInterceptor is upfront in the interceptor..."
which is reasonable because this interceptor keeps its stuff in thread local.
Questions:
1. Why is Spring APO implemented this way? Is it conceptually wrong to run different aspects in different threads? Are there workarounds except changing the aspects' order?
Why does HystrixCommandAspect call target class directly, but not through joinPoint.proceed()? Doesn't it break the contract (if one even exists)?
regards
Disclaimer: I am not a Spring or Hystrix user, just an AOP guy.
Why does HystrixCommandAspect call target class directly, but not through joinPoint.proceed()? Doesn't it break the contract (if one even exists)?
Actually, you have to ask the Hystrix maintainer. It is a good question, actually. the assumption that Hystrix aspects are the only ones in this universe is certainly a bold one because there actually is an AspectJ or Spring AOP contract for #Around advices:
Either the aspect calls the original method. If it does so, it ought to use proceed(). If it proceeds with the original method arguments or with a modified set, is up to the aspect. Also if it proceeds before, after or in between doing other things.
Or the aspect returns a result (for non-void methods) calculated without proceeding to the original method.
Or the aspect throws an exception, not returning any result.
Having said that, I think it is a design flaw in Hystrix not to pass on the ProceedingJoinPoint and eventually call proceed() on it in case the original method is to be called eventually. If I was a Hystrix user, I would open a bug ticket for that.
Besides, it is in principle no problem to call proceed() asynchronously from another thread in which you inject the joinpoint instance upon creation. Then you can put that thread (or a runnable) into a queue and execute it whenever convenient. Technically you can even call proceed() on the same joinpoint instance multiple times, but if the target method is no pure function without side effects you might want to be careful with that and usually won't do it unless your aspect implements some kind of retry scheme (with or without exponential back-off). So Hystrix could to that too. If they do not then they must be doing something ugly instead, such as use reflection to call the original method. I did not check.

Is it possible to resubmit a task to a Spring #Async method?

I have a Spring method annotated with #Async
#Async
public void doSomething(long id, String text) {
//do something
}
The method invokes a remote service, which occasionally times out. Is there a way to catch the timeout and resubmit the task to the #Async method N seconds later?
I doubt calling the annotated method from inside itself will work because Spring uses a pointcut to intercept invocations.
The only way I can think of is to override AsyncExecutionAspectSupport.handleError to rebuild an instanceof MethodInvocation and then call a copy of
AsyncExecutionInterceptor.invoke that lets me specify a delay.
Is there another way? Perhaps someone has already done it?
An Aside
I can imagine a solution whereby #Async is extended to specify cases for retry, in much the same way that transactions are managed in Spring but this is more fundamental than the theoretical solution described above!
#Async(retryOn=TimeoutException.class, maxRetries=2, delayStrategy=DelayStrategy.DOUBLE)

Asynchronously calling synchronized methods?

I want to benefit from asynchronously calling one of my methods. Since I use spring framework, this task is quite trivial, so I just marked the method with #Async annotation.
However my method is using a global variable that is not intended to be used concurrently by multiple threads( you may think of it as javax.jms.Session).
First thing that comes to mind to mark the method with synchronized keyword in order to make sure that method is thread safe.
But on the other hand it will be completely nonsense to use #Async annotation on synchronized method, right?
Is there any benefit to use #Async annotation on method that contains synchronized block ?
The purpose of making something asynchronous is that it will do things in the future, that will take relatively much time, for example file or database operation, and during that time, you can make other useful operations.
In your case, if you do synchronous block inside and async operation, you will lose async functionality making that part of your code block in certain cases. Of course, if you access a shared resource concurrently, you should defend it, the real question here, is that you really need async functionality inside that function? Maybe you can refactor your code to deal with the synchronous resource somewhere else.
Also if you are really into async functionality, and spring, you should check out Spring 5, and what it has to offer, when it's released.
Spring 5.x

What does an "asynchronous method" mean in Java?

I am in the process of working through the android billing example for an app. The sample app refers to an asynchronous method. I have had a look on the web and I cant seem to find a good definition, please can someone help with an example.
Sample as follows:
// Start setup. This is asynchronous and the specified listener
// will be called once setup completes.
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
Is it a method that does not immediately return a result?
If I am not mistaken, you are referring to this method startSetup that accepts a final OnIabSetupFinishedListener and supposedly sets up the billing.
What you seem to be confused about, is this rather syntactically obscure feature of Java called the anonymous inner class.
Let me attempt to answer your question to make it easier:
Is it a method that does not immediately return a result?
Yes, sort of (it of course does not return anything for it is a void method). It, simply speaking, is a method that accepts an instance of the interface OnIabSetupFinishedListener and does some of its job asynchronously as stated in the Javadoc and returns nothing:
This will start up the setup process asynchronously.
Thus, this method is similar to what any other void Java method looks like. The only additional implementation information is that some kind of communication is set up between the listener you pass to this method and some other objects.
But that communication is going to happen at a later point in time, not at the time you call this method, startSetup. Thus, what is important is the call site, i.e. how you are going to call this method in your own app. This, hopefully, happens at the time of setting up your app and you need to get it quickly running and hence this method provides a callback mechanism and returns as soon as possible in a synchronous manner without unnecessary delay. This means your calling thread can make progress and the listener you passed to this method can be utilized later in some other thread when an appropriate event occurs.
The confusion also comes in part because of the way anonymous inner classes are typically coded. Thus, your call site may look like the following:
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
// Oh noes, there was a problem.
Log.d(TAG, "Problem setting up In-app Billing: " + result);
}
// Hooray, IAB is fully set up!
}
});
Here, you are providing an anonymous implementation of the interface OnIabSetupFinishedListener directly at the call site (without actually creating a separate class implementing that interface, using the construct like class MyListener implements OnIabSetupFinishedListener).
Yes. In this context, "asynchronous" means that the method will return immediately and execution will continue with the statement following the method call. Sometime later, the onIabSetupFinished(...) method will be called on the listener. This is called a callback. An important consideration with asynchronous callbacks is what thread they are called in. You'll need to refer to the documentation for this API to find that out.
An asynchronous method is not a typically request/response
You can think of this like a promise or something that will reply without pooling.
In your case you are creating an anonymous listener that will resolve the promise here
public void onIabSetupFinished(IabResult result){
//you will eventually get the response here
}

Categories

Resources