本篇分析一下关于Orchestration-based saga的例子
示例项目https://github.com/eventuate-tram/eventuate-tram-sagas-examples-customers-and-orders
当order service创建一张订单后,会新建一个CreateOrderSagaData,然后createOrderSagaManager会根据CreateOrderSagaData建立一个saga
@Transactional
public Order createOrder(OrderDetails orderDetails) {
ResultWithEvents<Order> oe = Order.createOrder(orderDetails);
Order order = oe.result;
orderRepository.save(order);
CreateOrderSagaData data = new CreateOrderSagaData(order.getId(), orderDetails);
createOrderSagaManager.create(data, Order.class, order.getId());
return order;
}
package io.eventuate.examples.tram.sagas.ordersandcustomers.orders.sagas.createorder;
import io.eventuate.examples.tram.sagas.ordersandcustomers.commondomain.Money;
import io.eventuate.examples.tram.sagas.ordersandcustomers.customers.api.commands.ReserveCreditCommand;
import io.eventuate.examples.tram.sagas.ordersandcustomers.orders.commandsandreplies.ApproveOrderCommand;
import io.eventuate.examples.tram.sagas.ordersandcustomers.orders.commandsandreplies.RejectOrderCommand;
import io.eventuate.tram.commands.consumer.CommandWithDestination;
import io.eventuate.tram.sagas.orchestration.SagaDefinition;
import io.eventuate.tram.sagas.simpledsl.SimpleSaga;
import static io.eventuate.tram.commands.consumer.CommandWithDestinationBuilder.send;
public class CreateOrderSaga implements SimpleSaga<CreateOrderSagaData> {
private SagaDefinition<CreateOrderSagaData> sagaDefinition =
step()
.withCompensation(this::reject)
.step()
.invokeParticipant(this::reserveCredit)
.step()
.invokeParticipant(this::approve)
.build();
@Override
public SagaDefinition<CreateOrderSagaData> getSagaDefinition() {
return this.sagaDefinition;
}
private CommandWithDestination reserveCredit(CreateOrderSagaData data) {
long orderId = data.getOrderId();
Long customerId = data.getOrderDetails().getCustomerId();
Money orderTotal = data.getOrderDetails().getOrderTotal();
return send(new ReserveCreditCommand(customerId, orderId, orderTotal))
.to("customerService")
.build();
}
public CommandWithDestination reject(CreateOrderSagaData data) {
return send(new RejectOrderCommand(data.getOrderId()))
.to("orderService")
.build();
}
private CommandWithDestination approve(CreateOrderSagaData data) {
return send(new ApproveOrderCommand(data.getOrderId()))
.to("orderService")
.build();
}
}
createOrderSagaManager会根据CreateOrderSagaData找到同一目录下的CreateOrderSaga,CreateOrderSaga实现了SimpleSaga接口,所以CreateOrderSaga必须实现getSagaDefinition()方法,getSagaDefinition()会返回SagaDefiition。
SagaDefinition会定义事务调用顺序以及事务补偿方法。
上面的SagaDefinition一共定义了三个步奏:
- 首先定义了补偿事务
- 定义了第一个要处理的customer service中的reserveCredit local trasaction,saga会调用reserveCredit()方法来向kafka中的customerService channel发送ReserveCreditCommand,customerService会预先订阅customerService channel,接收到ReserveCreditCommand后会做出相应的操作。
- 当reserveCredit local trasaction处理成功后,第二个要处理的是order service中的approve local trasaction,saga会接着调用approve()方法向kafka中的orderService channel发送ApproveOrderCommand,orderService会预先订阅orderService channel,接收到ApproveOrderCommand后会做出相应的操作。
package io.eventuate.examples.tram.sagas.ordersandcustomers.customers.service;
import io.eventuate.examples.tram.sagas.ordersandcustomers.customers.api.commands.ReserveCreditCommand;
import io.eventuate.examples.tram.sagas.ordersandcustomers.customers.api.replies.CustomerCreditReservationFailed;
import io.eventuate.examples.tram.sagas.ordersandcustomers.customers.api.replies.CustomerCreditReserved;
import io.eventuate.examples.tram.sagas.ordersandcustomers.customers.domain.Customer;
import io.eventuate.examples.tram.sagas.ordersandcustomers.customers.domain.CustomerCreditLimitExceededException;
import io.eventuate.examples.tram.sagas.ordersandcustomers.customers.domain.CustomerRepository;
import io.eventuate.tram.commands.consumer.CommandHandlers;
import io.eventuate.tram.commands.consumer.CommandMessage;
import io.eventuate.tram.messaging.common.Message;
import io.eventuate.tram.sagas.participant.SagaCommandHandlersBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import static io.eventuate.tram.commands.consumer.CommandHandlerReplyBuilder.withFailure;
import static io.eventuate.tram.commands.consumer.CommandHandlerReplyBuilder.withSuccess;
public class CustomerCommandHandler {
@Autowired
private CustomerRepository customerRepository;
public CommandHandlers commandHandlerDefinitions() {
return SagaCommandHandlersBuilder
.fromChannel("customerService")
.onMessage(ReserveCreditCommand.class, this::reserveCredit)
.build();
}
public Message reserveCredit(CommandMessage<ReserveCreditCommand> cm) {
ReserveCreditCommand cmd = cm.getCommand();
long customerId = cmd.getCustomerId();
Customer customer = customerRepository.findOne(customerId);
// TODO null check
try {
customer.reserveCredit(cmd.getOrderId(), cmd.getOrderTotal());
return withSuccess(new CustomerCreditReserved());
} catch (CustomerCreditLimitExceededException e) {
return withFailure(new CustomerCreditReservationFailed());
}
}
// withLock(Customer.class, customerId).
// TODO @Validate to trigger validation and error reply
}
这个类定义了customerServive会订阅的customerService channel,和接收到相应的命令的处理方法
package io.eventuate.examples.tram.sagas.ordersandcustomers.orders.service;
import io.eventuate.examples.tram.sagas.ordersandcustomers.orders.commandsandreplies.RejectOrderCommand;
import io.eventuate.examples.tram.sagas.ordersandcustomers.orders.domain.Order;
import io.eventuate.examples.tram.sagas.ordersandcustomers.orders.domain.OrderRepository;
import io.eventuate.examples.tram.sagas.ordersandcustomers.orders.commandsandreplies.ApproveOrderCommand;
import io.eventuate.tram.commands.consumer.CommandHandlers;
import io.eventuate.tram.commands.consumer.CommandMessage;
import io.eventuate.tram.messaging.common.Message;
import io.eventuate.tram.sagas.participant.SagaCommandHandlersBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import static io.eventuate.tram.commands.consumer.CommandHandlerReplyBuilder.withSuccess;
public class OrderCommandHandler {
@Autowired
private OrderRepository orderRepository;
public CommandHandlers commandHandlerDefinitions() {
return SagaCommandHandlersBuilder
.fromChannel("orderService")
.onMessage(ApproveOrderCommand.class, this::approve)
.onMessage(RejectOrderCommand.class, this::reject)
.build();
}
public Message approve(CommandMessage<ApproveOrderCommand> cm) {
long orderId = cm.getCommand().getOrderId();
Order order = orderRepository.findOne(orderId);
order.noteCreditReserved();
return withSuccess();
}
public Message reject(CommandMessage<RejectOrderCommand> cm) {
long orderId = cm.getCommand().getOrderId();
Order order = orderRepository.findOne(orderId);
order.noteCreditReservationFailed();
return withSuccess();
}
}
这个类定义了orderService定义了订阅的orderService channel,和接收到相应的命令的处理方法