Не все ресурсы являются транзакционными. Электронная почта является одним из них. Таким образом, нельзя ожидать, что отправка электронной почты будет отменена, если другие транзакции не будут выполнены.
Есть несколько альтернативных решений:
1) вызывать ресурс без транзакций на последнем шаге.
Как и в примере создания пользователя. В этом случае все бизнес-ограничения проверяются и проходят, единственной причиной сбоя является проблема инфраструктуры, которая нередко случается в реальном мире (с тщательным обслуживанием). Сделайте некоторую компенсацию, если произойдет сбой инфраструктуры. Это можно сделать автоматически или вручную, в зависимости от того, как часто это происходит. Например, если письмо отправлено, но пользовательская настройка откат, вы можете сказать ему, что вам очень жаль (это очень важно: P), но что-то не так с настройкой, повторите попытку.
2) применяются в конечном итоге консистенция
Используйте транзакционный ресурс вместо того, чтобы запустить процесс. Например, вы можете использовать обмен сообщениями (глобально транзакционный, если использовать 2-фазную фиксацию), чтобы уведомлять об отправке писем.
CreateUser(...)
{
//1.) New up user object
//2.) Add newly created object to database
//3.) Publish user setup event by messaging
//4.) Commit transaction (ensures message is successfully sent AND object is created in database, else transaction fails
}
В любом случае, сбои и несоответствия происходят более или менее. Вы должны это сделать, это приемлемо.