Refactor AfterTransactionCommitDefaultServiceExecutor (#2143)
fixes transaction in transaction after commit (or at least makes is cleaner) Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -21,39 +21,36 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
|||||||
* The class is thread safe.
|
* The class is thread safe.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class AfterTransactionCommitDefaultServiceExecutor implements TransactionSynchronization, AfterTransactionCommitExecutor {
|
public class AfterTransactionCommitDefaultServiceExecutor implements AfterTransactionCommitExecutor {
|
||||||
|
|
||||||
private static final ThreadLocal<List<Runnable>> THREAD_LOCAL_RUNNABLES = new ThreadLocal<>();
|
private static class TransactionSynchronizationImpl implements TransactionSynchronization {
|
||||||
|
|
||||||
@Override
|
private final List<Runnable> afterCommitRunnables = new ArrayList<>();
|
||||||
// Exception squid:S1217 - Is aspectJ proxy
|
|
||||||
@SuppressWarnings({ "squid:S1217" })
|
|
||||||
public void afterCommit() {
|
|
||||||
final List<Runnable> afterCommitRunnables = THREAD_LOCAL_RUNNABLES.get();
|
|
||||||
if (afterCommitRunnables == null) {
|
|
||||||
log.trace("Transaction successfully committed, runnables is null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// removes the runnables that will process, so they would be able to start new transactions and
|
@Override
|
||||||
// inserting new after commit hooks
|
// Exception squid:S1217 - Is aspectJ proxy
|
||||||
THREAD_LOCAL_RUNNABLES.remove();
|
@SuppressWarnings({ "squid:S1217" })
|
||||||
log.debug("Transaction successfully committed, executing {} runnables", afterCommitRunnables.size());
|
public void afterCommit() {
|
||||||
for (final Runnable afterCommitRunnable : afterCommitRunnables) {
|
log.debug("Transaction successfully committed, executing {} runnables", afterCommitRunnables.size());
|
||||||
log.debug("Executing runnable {}", afterCommitRunnable);
|
for (final Runnable afterCommitRunnable : afterCommitRunnables) {
|
||||||
try {
|
log.debug("Executing runnable {}", afterCommitRunnable);
|
||||||
afterCommitRunnable.run();
|
try {
|
||||||
} catch (final RuntimeException e) {
|
afterCommitRunnable.run();
|
||||||
log.error("Failed to execute runnable {}", afterCommitRunnable, e);
|
} catch (final RuntimeException e) {
|
||||||
|
log.error("Failed to execute runnable {}", afterCommitRunnable, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({ "squid:S1217" })
|
@SuppressWarnings({ "squid:S1217" })
|
||||||
public void afterCompletion(final int status) {
|
public void afterCompletion(final int status) {
|
||||||
log.debug("Transaction completed after commit with status {}", status == STATUS_COMMITTED ? "COMMITTED" : "ROLLEDBACK");
|
log.debug("Transaction completed after commit with status {}", status == STATUS_COMMITTED ? "COMMITTED" : "ROLLEDBACK");
|
||||||
THREAD_LOCAL_RUNNABLES.remove();
|
}
|
||||||
|
|
||||||
|
private void afterCommit(final Runnable runnable) {
|
||||||
|
afterCommitRunnables.add(runnable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -62,17 +59,15 @@ public class AfterTransactionCommitDefaultServiceExecutor implements Transaction
|
|||||||
public void afterCommit(final Runnable runnable) {
|
public void afterCommit(final Runnable runnable) {
|
||||||
log.debug("Submitting new runnable {} to run after transaction commit", runnable);
|
log.debug("Submitting new runnable {} to run after transaction commit", runnable);
|
||||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||||
List<Runnable> localRunnables = THREAD_LOCAL_RUNNABLES.get();
|
TransactionSynchronizationManager.getSynchronizations().stream().filter(TransactionSynchronizationImpl.class::isInstance)
|
||||||
if (localRunnables == null) {
|
.map(TransactionSynchronizationImpl.class::cast).findAny().orElseGet(() -> {
|
||||||
localRunnables = new ArrayList<>();
|
final TransactionSynchronizationImpl newTS = new TransactionSynchronizationImpl();
|
||||||
THREAD_LOCAL_RUNNABLES.set(localRunnables);
|
TransactionSynchronizationManager.registerSynchronization(newTS);
|
||||||
TransactionSynchronizationManager.registerSynchronization(this);
|
return newTS;
|
||||||
}
|
}).afterCommit(runnable);
|
||||||
localRunnables.add(runnable);
|
} else {
|
||||||
return;
|
log.info("Transaction synchronization is NOT ACTIVE/ INACTIVE. Executing right now runnable {}", runnable);
|
||||||
|
runnable.run();
|
||||||
}
|
}
|
||||||
log.info("Transaction synchronization is NOT ACTIVE/ INACTIVE. Executing right now runnable {}", runnable);
|
|
||||||
|
|
||||||
runnable.run();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user