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

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)

Related

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.

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

Method with Spring #Async annotation not executed

I use spring #Async annotation to execute certain tasks. At some point (maybe because the pool-size was reached) I see in the debugger that the method with #Async is called but the break point in the method is not reached. I do not know it it will be called when another #Async method is finished or it is skipped forever.
I would like to know if it is possible to trigger an exception when there are not free #Async to execute it.
In addition, how can I know how many #Async are currently used at any given time
Thanks
Avi
At some point (maybe because the pool-size was reached) I see in the debugger that the method with #Async is called but the break point in the method is not reached.
Are you sure that the code fragment if not blocked by some conditional? Without a valid code sample, one can only speculate at this point.
I would like to know if it is possible to trigger an exception when there are not free #Async to execute it.
A TimeoutException is usually thrown in this case. You can modify the time out value by adding the following to your Spring config XML.
<mvc:annotation-driven>
<mvc:async-support default-timeout="180"/>
</mvc:annotation-driven>
Alternatively have a look at this answer: Providing a timeout value when using #Async for a method using Spring 3.0
In addition, how can I know how many #Async are currently used at any given time
Usually when you activate logging using e.g. sl4j inside the code executed inside an #Async method, you'll see the following output:
2017-03-10 10:27:41,910 [SimpleAsyncTaskExecutor-1] DEBUG
2017-03-10 10:27:43,282 [SimpleAsyncTaskExecutor-2] DEBUG
Hope that this helps!

Spring async method called from another async method

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.

Handling a timeout in EJB3 without using threads

I have the following situation. I have a job that:
May time out after a given amount of time, and if so occurs needs to throw an exception
If it does not time out, will return a result
If this job returns a result, it must be returned as quickly as possible, because performance is very much an issue. Asynchronous solutions are hence off the table, and naturally tying up the system by hammering isn't an option either.
Lastly, the system has to conform to the EJB standard, so AFAIK using ordinary threads is not an option, as this is strictly forbidden.
Our current solution uses a thread that will throw an exception after having existed for a certain amount of time without being interrupted by an external process, but as this clearly breaks the EJB standard, we're trying to solve it with some other means.
Any ideas?
Edited to add: Naturally, a job which has timed out needs to be removed (or interrupted) as well.
Edited to add 2:
This issue doesn't seem to have any solution, because detecting a deadlock seems to be mostly impossible sticking to pure EJB3 standards. Since Enno Shioji's comments below reflect this, I'm setting his suggestion as the correct answer.
This is more like a request for clarification, but it's too long to fit as a comment..
I'm not sure how you are doing it right now, since from what you wrote, just using the request processing thread seems to be the way to go. Like this:
//Some webservice method (synchronous)
public Result process(Blah blah){
try{
return getResult(TimeUnit.SECONDS, 10);
}catch(InterruptedException e){
//No result within 10 seconds!
throw new ServiceUnavailableException("blah");
}
}
I'm not sure why you are creating threads at all. If you are forced to use threads because the getResult method doesn't timeout at all, you would have a thread leak. If it timeouts after a longer time and thus you want to "shortcut" your reply to the user, that would be the only case I'd consider using a thread like I imagine how you are using it. This could result in Threads piling up under load and I'd strive to avoid such situation.
Maybe you can post some code and let us know why you are creating in your service at all?
Also, what's your client interface? Sounds like it's a synchronous webservice or something?
In that case, if I were you I would use a HashedWheelTimer as a singleton... this mechanism should work great with your requirement (here is an implementation). However, this unfortunately seem to conflict with the ban on threading AND the ban on singleton in the EJB spec. In reality though there really isn't a problem if you would do this. See this discussion for example. We have also used the singleton pattern in our EJB app. which used JBoss. However, if this isn't a viable choice then I might look at isolating the processing in its own JVM by defining a new web service (and deploy it in a web-container or something), and call that service from the EJB app. This would however obviously incur performance hit and now you would have another whole new app.
With Bean Managed Transaction, the timeout for the specific transaction can be specified by using UserTransaction interface.
Modify the timeout value that is
associated with transactions started
by the current thread with the begin
method.
void setTransactionTimeout(int seconds) throws SystemException
Transaction will timeout after specified seconds & may not get propagated further. If exception is not thrown implicitly, then can throw it explicitly based on the result.
Will return a result on successful completion within specified time.
Can use it with stateless session beans so there may not be a performance issue.
Its EJB standard so that will not be an issue to implement.
With little-bit work around, it should work fine in the given scenario.
Edit : Also can use server specific properties to manage transaction timeout.
JBoss : At either at class or method level annotation #TransactionTimeout(100) can be applied.
Weblogic : Specifying the parameters in weblogic-ejb-jar.xml
<transaction-descriptor>
<trans-timeout-seconds>100</trans-timeout-seconds>
</transaction-descriptor>
GlassFish : Using the optional cmt-timeout-in-seconds element in sun-ejb-jar.xml
Stick the process and it's timeout thread in to a class annotated with #WebService, put that class in to a WAR, then invoke the WebService from your EJB.
WARs don't have the same limitations or live under the same contract that EJBs do, so they can safely run threads.
Yes, I consider this a "hack", but it meets the letter of the requirements, and it's portable.
You can create threads using the commonj WorkManager. There are implementations built into WebSphere and Weblogic as they proposed the standard, but you can also find implementations for other appservers as well.
Basically, the WorkManager allows you to create managed threads inside the container, much like using an Executor in regular Java. Your only other alternative would be to use MDB's, but that would be a 'heavier' solution.
Since I don't know your actual platform, you will have to google commonj with your platform yourself 8-)
Here is a non IBM or Oracle solution.
Note: This is not an actual standard, but it is widely available for different platforms and should suit your purposes nicely.
For EJBs, there is a concept of "Container Managed Transactions". By specifying #TransactionAttribute on your bean, or specific method, the container will create a transaction when ever the method(s) are invoked. If the execution of the code takes longer than the transaction threshold, the container will throw an exception. If the call finishes under the transaction threshold, it will return as usual. You can catch the exception in your calling code and handle it appropriately.
For more on container managed transactions, check out: http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Transaction3.html and http://download.oracle.com/javaee/5/tutorial/doc/bncij.html
You could use #TimeOut. Something like:
#Stateless
public class TimedBean {
#Resource
private TimerService timerService;
static private AtomicInteger counter = new AtomicInteger(0);
static private Map<Integer, AtomicBoolean> canIRunStore = new ...;
public void doSomething() {
Integer myId = counter.getAndIncrement();
AtomicBoolean canIRun = new AtomicBoolean(true);
canIRunStore.put(myId, canIRun);
timerService.createTimer(1000, 0, myId);
while (canIRun.get() /* && some other condition */) {
// do my work ... untill timeout ...
}
}
#Timeout
#PermitAll
public void timeout(Timer timer) {
Integer expiredId = (Integer) timer.getInfo();
AtomicBoolean canHeRun = canIRunStore.get(expiredId);
canIRunStore.remove(expiredId);
canHeRun.set(false);
}
}

Categories

Resources