'Transaction rollback when @Async method fails
I am trying to read about Transaction but I cannot understand how would I rollback a async method call, is it even possible to do so.
I am facing an issue where User can select either select manual or driverless car for example. So if he selects driverless, then manual config will be disabled and other way round. Consider, he is moving from driverless to manual, driverless config is switched off and I make call to another service to switch off the manual configuration (which takes place in an Async call). I have added @Async
for a reason as it is time consuming call.
example
// Caller
@Override
public void enableDriverlessDriving(DriverlessDriving driverlessConfig) {
validator.validate(driverlessConfig);
driverlessDao.update(driverlessConfig);
if(drivelessConfig.isEnabled()) {
manualService.onDrivelessEnabled(driverlessConfig.getUserId());
}
}
// Callee
@Override
@Aysnc
public void onDrivelessEnabled(int userId) {
.....
// retrofit rest call. Timeout for 30 secs
ManualConfig config = client.getManualConfiguration(userid,30);
config.isEnabled(false);
try {
// retrofit rest call. timeout for 30 secs
client.updateManualConfig(config, userId,30);
}catch(CheckedExceptions e) { // throwing checked exceptions here.
LOGGER.error(...)
return;
}
}
If there is an invoke error for rest call to disable manual config, the driverless config is switched on but manual config is not switched off, both are turned on.
Question:
Adding
@Transactional
to the caller and callee method work? - May be, but then it will affect the performance, there would be no use of@Async
in this case.Should caller method have
@Transactional
, but the@Async
method should have@Transactional(REQUIRES_NEW)
? Would having rollback on the caller method@Transaction
rollback the transaction for checked exception in callee method?
I am expecting a solution where I achieve the integrity of data without compromising on performance (I want @Async
to work in a way it works now)
Solution 1:[1]
That's a great question, i came across at this some time ago.
- No, adding
@Transactional
is not going to work because when the@Async
method starts it is running on a new thread - I think there's no way to do a rollback based on a
@Async
method call. - You can get rollback to work without async calls, I don't know why you need to call the driverless method as
@Async
, but if you remove it will work.
Solution 2:[2]
I will not suggest to merge @Async
and @Transactional
so i can run the service in either way. I just create async wrapper around the service and use this one instead if needed.
@Transactional with @Async
when a @Transactional
Spring @Component
calls a method annotated with @Async
this does not happen. The call to the asynchronous method is being scheduled and executed at a later time by a task executor and is thus handled as a 'fresh' call, i.e. without a transactional context. If the @Async
method (or the @Component
in which it is declared) is not @Transactional
by itself Spring will not manage any needed transactions.
If the @Async
annotation is being used extra care should be taken with respect to transactions.In this case the transaction gets propagated through the call hierarchy from one Spring @Component
to the other.
In order to make Spring manage the transaction of the @Async
method either the @Component
or the method itself should declare the @Transactional
annotation, this way Spring
will manage the transaction even if a method is being executed asynchronous.
Solution 3:[3]
Try below approach,
- Create a separate class. Declare that as a bean under spring configuration.
- Add all async methods in this class.
- Autowire this class under the service class.
- Inside a Transactional method from service class, call async method from the class created in 1st step.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Sai prateek |
Solution 2 | Sai prateek |
Solution 3 | Nikhil |