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:
Avgustin Marinov
2024-12-11 16:00:10 +02:00
committed by GitHub
parent b6fa00cc3e
commit f813be87e5

View File

@@ -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();
} }
} }