Я слежу за Пример AxonBank, чтобы понять реализацию Saga во фреймворке Axon и иметь такой код для начала и завершения саги.
@Saga
public class MoneyTransferSaga {
@Inject
private transient CommandGateway commandGateway;
private String targetAccount;
private String transferId;
@StartSaga
@SagaEventHandler(associationProperty = "transferId")
public void on(MoneyTransferRequestedEvent event) {
System.out.println("Inside start saga for money transfer event");
targetAccount = event.getTargetAccount();
transferId = event.getTransferId();
SagaLifecycle.associateWith("transactionId", transferId);
System.out.println("## These are the params going into WMC : sourceAccount: " + event.getSourceAccount()
+ " transferID: " + transferId + " event.getAmount: " + event.getAmount());
commandGateway.send(new WithdrawMoneyCommand(event.getSourceAccount(), transferId, event.getAmount()),
new CommandCallback<WithdrawMoneyCommand, Object>() {
@Override
public void onSuccess(CommandMessage<? extends WithdrawMoneyCommand> commandMessage,
Object result) {
}
@Override
public void onFailure(CommandMessage<? extends WithdrawMoneyCommand> commandMessage,
Throwable cause) {
System.out.println("On failure of withdraw money command inside saga ");
System.out.println("###################### Cause of failure = " + cause);
commandGateway.send(new CancelMoneyTransferCommand(event.getTransferId()));
}
});
}
@SagaEventHandler(associationProperty = "transactionId")
public void on(MoneyWithdrawnEvent event) {
System.out.println("Inside saga event handler for monney withdrawnevent");
commandGateway.send(new DepositMoneyCommand(targetAccount, event.getTransactionId(), event.getAmount()),
LoggingCallback.INSTANCE);
}
@SagaEventHandler(associationProperty = "transactionId")
public void on(MoneyDepositedEvent event) {
System.out.println("Inside saga event handler for money deposited event");
commandGateway.send(new CompleteMoneyTransferCommand(transferId), LoggingCallback.INSTANCE);
}
@EndSaga
@SagaEventHandler(associationProperty = "transferId")
public void on(MoneyTransferCompletedEvent event) {
System.out.println("Inside Endsaga for money transfer complete event");
}
@SagaEventHandler(associationProperty = "transferId")
public void on(MoneyTransferCancelledEvent event) {
end();
}
}
После выполнения денежного перевода через REST API весь этот код запускается, поскольку я вижу, что мои журналы распечатываются на консоли, а все транзакции хранятся в таблице учетной записи.
Все записи также существуют в domain_event_entry, но таблицы saga_entry и association_value_entry остаются пустыми независимо от того, успешна ли транзакция или нет.
Сначала я подумал, что это может быть из-за неправильно настроенного хранилища саг, поэтому я настроил хранилище саг с MongoSagaStore
, но все же коллекция саги остается пустой.
Так что мне здесь чего-то не хватает, или аксон просто удаляет данные из этих таблиц после завершения саги?
AxonFramework автоматически удалит запись саги из своего хранилища, включая любые ассоциации, когда она закончится. Таким образом, вы всегда будете видеть информацию только об активных экземплярах.
В примере приложения все компоненты шины используют реализацию «Simple ...», что в основном означает, что все действия выполняются в одном потоке. Следовательно, как только вы получите OK или NotOK, все действия Saga также будут прекращены. Если бы вы заменили их реализациями Async или Distributed, это уже не так. Вам вернут ОК до завершения всего процесса.
Он делает это специально, потому что «сложная бизнес-операция», которую обозначает сага, округляется в большую сторону. То, что сделано, не обязательно должно задерживаться. Кроме того, репозиторий Saga не служит для выполнения запросов, он просто служит способом сохранить «сложную бизнес-транзакцию», которую можно будет забрать позже. Тем не менее, самый простой способ не удалять сагу - это не вызывать функцию SagaLifecycle.end()
и не добавлять аннотацию @EndSaga
к каким-либо обработчикам событий.
Моей первой мыслью было не завершение саги. Я подумал, есть ли какая-то конфигурация вместо этого, но ваше объяснение имеет большой смысл, поэтому технически единственный след существования саги после ее окончания находится в domain_event_entry.
@Allard, я понимаю поведение хранилища Saga в примере AxonBank. Однако в примере AxonTrader (github.com/AxonFramework/Axon-trader) саги о продаже / покупке не завершаются в одном потоке, они могут охватывать несколько взаимодействий с пользователем. Однако я до сих пор не вижу постоянства саги в таблице SAGAENTRY. Это все сделано в памяти? Что будет, если произойдет перезагрузка сервера? (Я понимаю, что в этом примере используется hsql в памяти, я говорю, что если это делается в реальной базе данных, поведение сохраняемости должно быть таким же). Любой пример, демонстрирующий настойчивость саги, будет очень полезен.
есть ли способ изменить это поведение или Axon делает это специально?