AI Briefing
KO

Overcoming the Limits of a Legacy Alimtalk Sending System with Spring Transaction Synchronization

·2026.02.24 00:00

Key point

By separating Alimtalk delivery using Spring transaction synchronization and Kafka, the team improved consistency and scalability.

1 / 2

Details

The Alimtalk (notification message) sending system of Oliveyoung Delivery Squad is responsible for core customer experiences such as orders, payments, and delivery, but as the legacy structure grew more complex, it revealed limits in changing and scaling the sending platform.

Previously, the sending service was called directly inside the order/delivery status-change logic, and failures were absorbed with try-catch. However, if the business logic failed after an Alimtalk message had already been sent successfully, there was no way to undo the notification already sent, and re-execution also created a risk of duplicate sends.

The key to the transition was a structure that publishes messages only after the transaction commits. Initially, @TransactionalEventListener was considered, but practical application was difficult due to the legacy environment being below Spring 4.2, combined with dependency conflicts and NoClassDefFoundError issues.

Instead, TransactionSynchronizationManager was used to register a post-commit callback. Although this implementation is a callback rather than an event listener, it achieves the same effect in that subsequent processing only begins after the data is finalized, allowing Alimtalk sending to be safely separated from the business transaction.

The subsequent flow was organized around a Kafka-based event architecture.

  • In the legacy system, after an order/delivery status change, a message containing only the minimum required information is published
  • The Delivery Consumer consumes the message and takes full responsibility for sending
  • Depending on the Alimtalk type, it branches into general delivery, Today Dream, pickup, gifting, etc.
  • Within each delivery type, conditions such as general/exchange/cancellation are further divided, and common queries are organized accordingly
  • Template composition and send requests are unified into a single common API

With roughly 40 Alimtalk types, the design and classification work was not easy, but as a result, the lookup logic that was previously scattered across services in the legacy system was consolidated under common criteria. Failed messages are stored separately in the DB so they can be reprocessed, and for cases requiring even higher reliability, an Outbox Pattern or retry mechanism was noted as something that could be considered.

After the overhaul, the structure became much simpler. The send timing is guaranteed via afterCommit, data lookup has been unified under common criteria, and notification responsibility has been consolidated into the Delivery Consumer. As a result, adding new Alimtalk types can now be handled simply by registering a template and publishing a message, significantly improving maintainability and scalability.

The lessons learned from this project were also clear. It's necessary to understand the overall flow and architecture before writing code, and in an MSA environment, data flow and consistency must be designed not just within a single service but across systems. Through repeated testing with QA, the team confirmed that even small omissions can significantly affect the customer experience, and the project became an opportunity to broaden their perspective beyond simply fixing legacy code to thinking from a design standpoint.

This summary was generated automatically by AI. Check the original for the author's claims and context. Copyright belongs to the original author.

Our guide explains how the AI works. Report summary errors, attribution issues, or removal requests via Contact.