feat: transactional outbox pattern - #3589
Conversation
Introduce a new transactional-outbox Maven module demonstrating the Transactional Outbox pattern. Adds a Spring Boot sample app and README explaining the pattern. New code includes Order and OutboxEvent entities, OrderStatus/EventStatus enums, Spring Data repositories (OrderRepository, OutboxRepository), OrderService (atomic write of order + outbox), OutboxPublisher (scheduled poll & publish), MessageBroker interface and MessageConsumer implementation, and App entrypoint. Includes unit tests (AppTest, OrderServiceTest, OutboxPublisherTest). Root pom.xml updated to register the new module. Module uses Spring Data JPA, Spring Web, Lombok, H2 and standard test dependencies.
PR SummaryIntroduced the Transactional Outbox Pattern module to demonstrate reliable event publishing in microservices. The module persists orders and OutboxEvent within a single transactional boundary and uses a scheduled OutboxPublisher to dispatch events to a message broker. Includes entities, repositories, services, a Spring Boot demo App, tests, and README documentation. Changes
autogenerated by presubmit.ai |
There was a problem hiding this comment.
✅ LGTM!
Review Summary
Commits Considered (1)
- 4925e7e: Add transactional-outbox module
Introduce a new transactional-outbox Maven module demonstrating the Transactional Outbox pattern. Adds a Spring Boot sample app and README explaining the pattern. New code includes Order and OutboxEvent entities, OrderStatus/EventStatus enums, Spring Data repositories (OrderRepository, OutboxRepository), OrderService (atomic write of order + outbox), OutboxPublisher (scheduled poll & publish), MessageBroker interface and MessageConsumer implementation, and App entrypoint. Includes unit tests (AppTest, OrderServiceTest, OutboxPublisherTest). Root pom.xml updated to register the new module. Module uses Spring Data JPA, Spring Web, Lombok, H2 and standard test dependencies.
Files Processed (17)
- pom.xml (1 hunk)
- transactional-outbox/README.md (1 hunk)
- transactional-outbox/pom.xml (1 hunk)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/App.java (1 hunk)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/EventStatus.java (1 hunk)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/MessageBroker.java (1 hunk)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/MessageConsumer.java (1 hunk)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/Order.java (1 hunk)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/OrderRepository.java (1 hunk)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/OrderService.java (1 hunk)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/OrderStatus.java (1 hunk)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/OutboxEvent.java (1 hunk)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/OutboxPublisher.java (1 hunk)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/OutboxRepository.java (1 hunk)
- transactional-outbox/src/test/java/com/iluwatar/transactionaloutbox/AppTest.java (1 hunk)
- transactional-outbox/src/test/java/com/iluwatar/transactionaloutbox/OrderServiceTest.java (1 hunk)
- transactional-outbox/src/test/java/com/iluwatar/transactionaloutbox/OutboxPublisherTest.java (1 hunk)
Actionable Comments (0)
Skipped Comments (0)
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3589 +/- ##
============================================
+ Coverage 83.69% 83.72% +0.02%
- Complexity 4257 4272 +15
============================================
Files 1115 1121 +6
Lines 15066 15144 +78
Branches 721 723 +2
============================================
+ Hits 12610 12679 +69
- Misses 2161 2167 +6
- Partials 295 298 +3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Add two unit tests for OutboxPublisher: one verifies processOutboxEvents returns an empty list when there are no pending events; the other simulates a MessageBroker exception to ensure the event status is set to FAILED and the repository.save is called. Added necessary Mockito and assertion imports to support the tests.
Replace the legacy inline/mock-based test with a JUnit5 + MockitoExtension unit test. Adds OutboxPublisherUnitTest (uses @ExtendWith(MockitoExtension.class), @mock and @Injectmocks) that verifies broker exceptions mark events as FAILED and that the repository.save(...) is called. Removes the duplicate inline-mocking test and unused Mockito imports from OutboxPublisherTest.
There was a problem hiding this comment.
✅ LGTM!
Review Summary
Commits Considered (1)
- b46109e: Use MockitoExtension for OutboxPublisher test
Replace the legacy inline/mock-based test with a JUnit5 + MockitoExtension unit test. Adds OutboxPublisherUnitTest (uses @ExtendWith(MockitoExtension.class), @mock and @Injectmocks) that verifies broker exceptions mark events as FAILED and that the repository.save(...) is called. Removes the duplicate inline-mocking test and unused Mockito imports from OutboxPublisherTest.
Files Processed (2)
- transactional-outbox/src/test/java/com/iluwatar/transactionaloutbox/OutboxPublisherTest.java (1 hunk)
- transactional-outbox/src/test/java/com/iluwatar/transactionaloutbox/OutboxPublisherUnitTest.java (1 hunk)
Actionable Comments (0)
Skipped Comments (3)
-
transactional-outbox/src/test/java/com/iluwatar/transactionaloutbox/OutboxPublisherTest.java [57-59]
best_practice: "Graceful handling of empty outbox"
-
transactional-outbox/src/test/java/com/iluwatar/transactionaloutbox/OutboxPublisherTest.java [68-75]
testing: "End-to-end state validation after processing"
-
transactional-outbox/src/test/java/com/iluwatar/transactionaloutbox/OutboxPublisherTest.java [60-65]
testing: "Improve coverage for failure path and success path"
There was a problem hiding this comment.
🚨 Pull request needs attention.
Review Summary
Commits Considered (1)
Remove Lombok's @slf4j and add explicit org.slf4j.Logger/LoggerFactory fields in transactional-outbox classes.
This makes logging explicit and removes reliance on Lombok's @slf4j annotation.
Files Processed (4)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/App.java (1 hunk)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/MessageConsumer.java (1 hunk)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/OrderService.java (1 hunk)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/OutboxPublisher.java (1 hunk)
Actionable Comments (1)
-
transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/OutboxPublisher.java [53-58]
best_practice: "Scheduled method should return void"
Skipped Comments (5)
-
transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/App.java [69-72]
possible_bug: "Potential null IDs when logging after transactional creates"
-
transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/App.java [74-76]
best_practice: "Directly invoking scheduled method"
-
transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/App.java [79-82]
maintainability: "Thread-safety considerations for in-memory broker"
-
transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/MessageConsumer.java [41-47]
possible_issue: "Null payload safety on publish"
-
transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/OutboxPublisher.java [66-69]
performance: "Suggest batch update for efficiency"
Introduce publishOutboxEvents() annotated with @scheduled(fixedDelay = 5000) that delegates to the existing processOutboxEvents(). This separates the scheduling concern from the transactional processing method; processOutboxEvents() remains @transactional and now only handles fetching and dispatching pending OutboxEvent items.
Use UTC for timestamps in OrderService and OutboxPublisher by switching LocalDateTime.now() to LocalDateTime.now(ZoneOffset.UTC). Replace Lombok @requiredargsconstructor on OutboxPublisher with an explicit constructor for dependency injection and remove the @transactional annotation from processOutboxEvents. Update processedAt assignment to use UTC as well.
There was a problem hiding this comment.
🚨 Pull request needs attention.
Review Summary
Commits Considered (1)
- 97aea79: Use UTC timestamps and add OutboxPublisher ctor
Use UTC for timestamps in OrderService and OutboxPublisher by switching LocalDateTime.now() to LocalDateTime.now(ZoneOffset.UTC). Replace Lombok @requiredargsconstructor on OutboxPublisher with an explicit constructor for dependency injection and remove the @transactional annotation from processOutboxEvents. Update processedAt assignment to use UTC as well.
Files Processed (2)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/OrderService.java (1 hunk)
- transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/OutboxPublisher.java (1 hunk)
Actionable Comments (1)
-
transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/OrderService.java [76-80]
possible bug: "Locale-sensitive JSON payload formatting"
Skipped Comments (2)
-
transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/OutboxPublisher.java [54-57]
possible issue: "Scheduled publisher potential multi-instance concurrency"
-
transactional-outbox/src/main/java/com/iluwatar/transactionaloutbox/OutboxPublisher.java [65-78]
possible issue: "Potential race/duplication risk when processing pending events"
|
@iluwatar Please review |
Adds the Transactional Outbox Pattern (
transactional-outbox) module to the pattern catalog using Spring Boot.Order) and outbound events (OutboxEvent) into the database within a single@Transactionalboundary. A background@Scheduledservice (OutboxPublisher) periodically polls pending events and dispatches them to the message broker.Order&OutboxEvent: Spring Data JPA entities.OrderService:@Transactionalservice performing atomic dual-writes.OutboxPublisher: Background worker pollingPENDINGoutbox events and updating status toPROCESSED.README.md: Complete documentation including architecture flow, Mermaid class diagram, and programmatic examples.@SpringBootTestand H2 in-memory database.Fixes : 3531