Leveraging Spring Transaction Hooks with TransactionSynchronizationManager for Asynchronous Kafka Messaging
This article explains how to use Spring's TransactionSynchronizationManager to detect active transactions, register synchronization callbacks, and asynchronously send Kafka messages only after transaction commit, illustrated with a payment‑system example, code snippets, and practical deployment considerations.
The author, a senior architect, introduces a practical case where a payment system must archive each account's fund flow by publishing a Kafka message after the database transaction commits, ensuring data consistency and avoiding interference with the main business logic.
To meet the requirement, a lightweight second‑party library is designed as a Spring Boot starter that directly uses the Kafka producer API instead of Spring's KafkaTemplate, minimizing integration friction and providing a simple API for developers.
The core challenge is to determine whether a transaction is currently active and to trigger custom logic only after the transaction successfully commits. This is achieved by querying TransactionSynchronizationManager.isSynchronizationActive() and registering a TransactionSynchronizationAdapter via TransactionSynchronizationManager.registerSynchronization().
The following pseudocode demonstrates the solution:
private final ExecutorService executor = Executors.newSingleThreadExecutor();
public void sendLog() {
// Check if a transaction is active
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
// No transaction – send message asynchronously
executor.submit(() -> {
try {
// send message to Kafka
} catch (Exception e) {
// log exception, notify developers
}
});
return;
}
// Transaction is active – register a synchronization callback
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCompletion(int status) {
if (status == TransactionSynchronization.STATUS_COMMITTED) {
// After commit, send message asynchronously
executor.submit(() -> {
try {
// send message to Kafka
} catch (Exception e) {
// log exception, notify developers
}
});
}
}
});
}The code relies on the static, thread‑local synchronizations field inside TransactionSynchronizationManager, which is populated when Spring's transaction manager calls initSynchronization() at transaction start. When the transaction ends, Spring iterates over the registered synchronizations and invokes their callbacks.
By using this approach, the library ensures that Kafka messages are only sent after the surrounding transaction has been committed, preserving data integrity while keeping the main business flow unaffected.
At the end of the article, the author adds promotional material for a ChatGPT‑focused community, private accounts, and various paid services, which are unrelated to the technical content but serve as marketing outreach.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
