Используя сагу, учитывая событие EventA, сага запускается, она отправляет команду (или многие). Как мы можем убедиться, что команда успешно отправлена, тогда фактическая логика в другом микро-сервисе не сработала и т. Д.
Давайте рассмотрим пример саги по электронной почте: когда пользователь регистрируется, мы создаем агрегат пользователя, которыйпубликует UserRegisteredEvent, будет создана сага, и эта сага отвечает за то, чтобы убедиться, что регистрационное электронное письмо отправлено пользователю (электронное письмо может содержать ключ подтверждения, приветственное сообщение и т. д.).
Если мы используем:
commandGateway.sendAndWait
с попыткой / уловом -> масштабируется?
commandGateway.send
и использует крайний срок и использует какое-то "событие сбоя"«подобно SendEmailFailedEvent -> требует связать« токен »для команд, чтобы можно было связать« associationProperty »с правильной сагой, отправившей SendRegistrationEmailCommand
commandGateway.send(...).handle(...)
-> в дескрипторе. eventGateway / commandGateway, которые были в MyEmailSaga? Если ошибка, мы отправляем событие? Или мы можем изменить / вызвать метод из экземпляра саги, который у нас был. Если нет ошибок, то другие службы отправили событие, подобное «RegistrationEmailSentEvent», поэтому сага будет завершена.
использовать крайний срок, потому что мы просто используем «отправить» и не обрабатываем возможную ошибку командыкоторые, возможно, не были отправлены (другие службы не работают и т. д.)
что-то еще?
Или комбинация всех?
Как обрабатывать ошибки ниже? (используйте крайний срок или .handle (...) или другое)
Возможны следующие ошибки:
команда не имеет обработчиков (нет обслуживания и т. д.)
команда была обработана, но возникла исключительная ситуация в другой службе, и никакое событие не отправлено (без попытки / перехвата в другой службе)
команда была обработана, исключениеПоднятый и перехваченный, другой сервис публикует событие, чтобы уведомить о том, что ему не удалось отправить электронное письмо (сага получит событие и предпримет соответствующие действия в зависимости от типа события и предоставленных данных -> возможно, электронное письмо неверно или не существует, поэтому не нужно повторять попытку)
другие ошибки, которые я пропустил?
@Saga
public class MyEmailSaga {
@Autowired
transient CommandGateway commandGateway;
@Autowired
transient EventGateway eventGateway;
@Autowired
transient SomeService someService;
String id;
SomeData state;
/** count retry times we send email so can apply logic on it */
int sendRetryCount;
@StartSaga
@SagaEventHandler(associationProperty = "id")
public void on(UserRegisteredEvent event) {
id = event.getApplicationId();
//state = event........
// what are the possibilities here?
// Can we use sendAndWait but it does not scale very well, right?
commandGateway.send(new SendRegistrationEmailCommand(...));
// Is deadline good since we do not handle the "send" of the command
}
// Use a @DeadlineHandler to retry ?
@DeadlineHandler(deadlineName = "retry_send_registration_email")
fun on() {
// resend command and re-schedule a deadline, etc
}
@EndSaga
@SagaEventHandler(associationProperty = "id")
public void on(RegistrationEmailSentEvent event) {
}
}
РЕДАКТИРОВАТЬ (после принятого ответа):
В основном два варианта (извините, но код котлина ниже):
Первый вариант
commandGateway.send(SendRegistrationEmailCommand(...))
.handle({ t, result ->
if (t != null) {
// send event (could be caught be the same saga eventually) or send command or both
}else{
// send event (could be caught be the same saga eventually) or send command or both
}
})
// If not use handle(...) then you can use thenApply as well
.thenApply { eventGateway.publish(SomeSuccessfulEvent(...)) }
.thenApply { commandGateway.send(SomeSuccessfulSendOnSuccessCommand) }
2-й вариант: Используйте крайний срок, чтобы убедиться, что сагасделать что-то, если SendRegistrationEmailCommand не удалось, и вы не получили никаких событий в случае сбоя (когда вы не обрабатываетекоманда отправлена).
Конечно, можно использовать крайний срок для других целей.
Когда команда SendRegistrationEmailCommand была успешно получена, получатель опубликует событие, поэтому сага будет уведомлена и будет действовать в соответствии с ним. Может быть RegistrationEmailSentEvent или RegistrationEmailSendFailedEvent.
Сводка:
Кажется, что лучше использовать handle()
только в том случае, если команда не была отправлена или получатель получилнеожиданное исключение, если так, то опубликуйте событие для саги, чтобы воздействовать на него. В случае успеха получатель должен опубликовать событие, сага его прослушает (и в конечном итоге зарегистрирует крайний срок на всякий случай);Получатель может также отправить событие, чтобы уведомить об ошибке и не бросать, сага также будет слушать это событие.