Skip to content

Commit bcaaebe

Browse files
committed
Fix CreateOrderSaga completion and LazyInitializationException in order operations
- Add EventuateLocal CDC pipeline for accounting service alongside Tram pipeline The accounting service uses event sourcing (events table) for domain events but also needs the Tram pipeline (message table) for saga replies. Both pipelines share reader5. - Fix LazyInitializationException in OrderServiceImpl.reviseOrder() and cancel() by eagerly loading orderLineItems within the transaction - Remove unnecessary saga lock from KitchenServiceCommandHandler.createTicket() Co-authored by Claude Code
1 parent 7545eea commit bcaaebe

4 files changed

Lines changed: 33 additions & 8 deletions

File tree

ftgo-end-to-end-tests/src/endToEndTest/java/net/chrisrichardson/ftgo/endtoendtests/ApplicationUnderTestUsingTestContainers.java

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,19 +90,26 @@ public ApplicationUnderTestUsingTestContainers() {
9090
apiGateway = createApiGatewayContainer();
9191

9292
// CDC service
93+
// Note: Accounting service needs BOTH pipelines:
94+
// - Tram pipeline (message table) for sending saga replies
95+
// - EventuateLocal pipeline (events table) for publishing domain events
96+
// Both pipelines share the same reader (reader5)
9397
cdc = new EventuateCdcContainer()
9498
.withKafka(kafka)
9599
.withKafkaLeadership()
96-
.withTramPipeline(consumerDatabase)
97-
.withTramPipeline(orderDatabase)
98-
.withTramPipeline(kitchenDatabase)
99-
.withTramPipeline(restaurantDatabase)
100-
.withTramPipeline(accountingDatabase)
101-
.withTramPipeline(deliveryDatabase)
100+
.withTramPipeline(consumerDatabase) // reader1, pipeline1
101+
.withTramPipeline(orderDatabase) // reader2, pipeline2
102+
.withTramPipeline(kitchenDatabase) // reader3, pipeline3
103+
.withTramPipeline(restaurantDatabase) // reader4, pipeline4
104+
.withTramPipeline(accountingDatabase) // reader5, pipeline5 (Tram for saga replies)
105+
.withTramPipeline(deliveryDatabase) // reader6, pipeline6
102106
.withReuse(false)
103107
.withExposedPorts(8080)
104108
.dependsOn(consumerService, orderService, kitchenService, restaurantService, accountingService, deliveryService)
105109
.withLogConsumer(new Slf4jLogConsumer(logger).withPrefix("cdc:"));
110+
111+
// Add EventuateLocal pipeline for accounting service (reuses reader5, new pipeline7)
112+
addEventuateLocalPipelineUsingExistingReader(cdc, 5, 7);
106113
}
107114

108115
private EventuateDatabaseContainer<?> createDatabase(String alias) {
@@ -164,6 +171,20 @@ private GenericContainer<?> createApiGatewayContainer() {
164171
.withLogConsumer(new Slf4jLogConsumer(logger).withPrefix("api-gateway:"));
165172
}
166173

174+
/**
175+
* Adds an EventuateLocal pipeline that reuses an existing reader.
176+
* This allows the same database to have both Tram and EventuateLocal pipelines.
177+
*/
178+
private void addEventuateLocalPipelineUsingExistingReader(EventuateCdcContainer cdc, int readerIdx, int pipelineIdx) {
179+
String pipelinePrefix = "EVENTUATE_CDC_PIPELINE_PIPELINE" + pipelineIdx + "_";
180+
181+
// Pipeline configuration - uses eventuate-local type and existing reader
182+
// Note: accounting-service uses schema=public (per its application.properties)
183+
cdc.withEnv(pipelinePrefix + "TYPE", "eventuate-local");
184+
cdc.withEnv(pipelinePrefix + "READER", "reader" + readerIdx);
185+
cdc.withEnv(pipelinePrefix + "EVENTUATEDATABASESCHEMA", "public");
186+
}
187+
167188
@Override
168189
public void start() {
169190
kafka.withLogConsumer(new Slf4jLogConsumer(logger).withPrefix("kafka:"));

ftgo-kitchen-service/kitchen-service-command-handlers/src/main/java/net/chrisrichardson/ftgo/kitchenservice/messagehandlers/KitchenServiceCommandHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ private Message createTicket(CommandMessage<CreateTicket>
4747
try {
4848
Ticket ticket = kitchenService.createTicket(restaurantId, ticketId, ticketDetails);
4949
CreateTicketReply reply = new CreateTicketReply(ticket.getId());
50-
return withLock(Ticket.class, ticket.getId()).withSuccess(reply);
50+
return withSuccess(reply);
5151
} catch (RestaurantDetailsVerificationException e) {
5252
return withFailure();
5353
}

ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/messagehandlers/KitchenServiceCommandHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ private Message createTicket(CommandMessage<CreateTicket>
4747
try {
4848
Ticket ticket = kitchenService.createTicket(restaurantId, ticketId, ticketDetails);
4949
CreateTicketReply reply = new CreateTicketReply(ticket.getId());
50-
return withLock(Ticket.class, ticket.getId()).withSuccess(reply);
50+
return withSuccess(reply);
5151
} catch (RestaurantDetailsVerificationException e) {
5252
return withFailure();
5353
}

ftgo-order-service/order-service-main/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderServiceImpl.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ public Order cancel(Long orderId) {
126126
.orElseThrow(() -> new OrderNotFoundException(orderId));
127127
CancelOrderSagaData sagaData = new CancelOrderSagaData(order.getConsumerId(), orderId, order.getOrderTotal());
128128
sagaInstanceFactory.create(cancelOrderSaga, sagaData);
129+
// Access lazy-loaded collections within transaction to avoid LazyInitializationException
130+
order.getOrderTotal();
129131
return order;
130132
}
131133

@@ -163,6 +165,8 @@ public Order reviseOrder(long orderId, OrderRevision orderRevision) {
163165
Order order = orderRepository.findById(orderId).orElseThrow(() -> new OrderNotFoundException(orderId));
164166
ReviseOrderSagaData sagaData = new ReviseOrderSagaData(order.getConsumerId(), orderId, null, orderRevision);
165167
sagaInstanceFactory.create(reviseOrderSaga, sagaData);
168+
// Access lazy-loaded collections within transaction to avoid LazyInitializationException
169+
order.getOrderTotal();
166170
return order;
167171
}
168172

0 commit comments

Comments
 (0)