28 April, 2013

Operation Logic Executor - Combine fake locking with asynchronous execution

   Combining both solutions is trivial since I used aspects for them. I need to add @ResourceLock to my asynchronous method.
@Component
public class StringProcessingLogic implements OperationLogic<string> {

    private final Logger logger = LogManager.getLogger(StringProcessingLogic.class); 

    @ResourceLock
    @Async("singleOperationExecutor")
    public Future<boolean> executeOperation(OperationData<string> data) throws OperationFailedException {
        boolean result = false;
        try {
            long startTime = System.currentTimeMillis();
            do {
                logger.info("processing " + data);
                Thread.sleep(500);
            } while (startTime + 10000 > System.currentTimeMillis());
            result = true;
        } catch (InterruptedException e) {
            logger.error(e);
        }
        return new AsyncResult<boolean>(result);
    }

}
Let's check the result
20:37:10.603 [main] INFO  pl.mariusz.marciniak.async.AsyncMainTest - starting asynchronous test
20:37:10.629 [main] INFO  pl.mariusz.marciniak.async.AsyncMainTest - executing other logic ...
20:37:10.635 [singleOperationExecutor-1] DEBUG pl.mariusz.marciniak.locking.aop.ResourceLockAspect - acquiring lock on really long calculations::calculation data
20:37:10.635 [singleOperationExecutor-1] INFO  pl.mariusz.marciniak.async.StringProcessingLogic - processing really long calculations::calculation data
...
20:37:20.137 [singleOperationExecutor-1] INFO  pl.mariusz.marciniak.async.StringProcessingLogic - processing really long calculations::calculation data
20:37:20.638 [singleOperationExecutor-1] DEBUG pl.mariusz.marciniak.locking.aop.ResourceLockAspect - releasing lock on really long calculations::calculation data
20:37:20.638 [singleOperationExecutor-1] DEBUG pl.mariusz.marciniak.locking.aop.ResourceLockAspect - acquiring lock on transformation::transformed data
20:37:20.638 [singleOperationExecutor-1] INFO  pl.mariusz.marciniak.async.StringProcessingLogic - processing transformation::transformed data
...
20:37:30.138 [singleOperationExecutor-1] INFO  pl.mariusz.marciniak.async.StringProcessingLogic - processing transformation::transformed data
20:37:30.638 [singleOperationExecutor-1] DEBUG pl.mariusz.marciniak.locking.aop.ResourceLockAspect - releasing lock on transformation::transformed data

I’ve used executor with single thread so the result is as desired. The most important thing is that asynchronous execution takes precedence before locking. That is very good, in other way resources will be locked, method invoked asynchronously will immediately  returned and resources released before finishing asynchronous execution. So that’s REALLY great. Nice. Yeah, but why?

What exactly is defining order of different aspects invocation at the same join point? Well Spring documentation states:
When two pieces of advice defined in different aspects both need to run at the same join point, unless you specify otherwise the order of execution is undefined. You can control the order of execution by specifying precedence. This is done in the normal Spring way by either implementing the org.springframework.core.Ordered interface in the aspect class or annotating it with the Order annotation. Given two aspects, the aspect returning the lower value from Ordered.getValue() (or the annotation value) has the higher precedence.
For test purpose I will change my locking annotation order to be executed before @Async
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface ResourceLock {
}
In fact setting @ResourceLock to have the highest precedence (@Order equal the lowest integer), doesn’t change application’s behaviour. This is because AsyncAnnotationBeanPostProcessor has set beforeExistingAdvisors property to true and always adds @Async advistor before others. According to Spring creators:
@Async always needs to be the first Advisor in the chain in order to provide meaningful around-invocation semantics 
It means that Spring provides correct ordering and I don't need to change anything in my code.

No comments:

Post a Comment