У меня есть команда в .NET, которая создает некоторые объекты и возвращает результат. Во время команды он отправляет электронное письмо с информацией об объекте. Он использует службу, которую я получаю с помощью DI, и вызов является асинхронным. При тестировании я вижу, что отправка этого письма может привести к тому, что запрос займет вдвое больше времени. Код примерно такой.
public Guid CreateInvoice(string email, string name, ...)
{
var transaction = await _context.Databse.BeginTransactionAsync();
try {
await _context.Invoice.AddAsync(new Invoice(email, name));
// Some other CRUD operations here
await _emailService.SendEmail(email, name); // This here adds the latency
// Some other CRUD
transaction.Commit();
return newInvoice.Id;
}
catch(Exception e)
{
transaction.Rollback();
}
}
Я попытался удалить await из вызова метода электронной почты. Это, очевидно, ускоряет код, но тогда я не знаю, был ли отправлен метод, а это значит, что я не могу откатить транзакцию, если возникнет проблема. Я хочу откатить весь CRUD, если метод не отправлен.
Какой здесь лучший подход? Должен ли я добавить какую-нибудь политику повторных попыток для отправки, чтобы мне не приходилось беспокоиться об откате. Должен ли я добавить в службу электронной почты какой-то метод, который уведомляет пользователя об ошибке в случае сбоя метода? Возможно, я смогу разделить их, а затем вызвать отправку электронной почты в фоновом режиме, чтобы она работала сама по себе. Я открыт для любых идей о том, как с этим справиться. Заранее спасибо.
Бизнес-логика заключается в том, что когда пользователь создает счет-фактуру, он ожидает отправки электронного письма. Я думаю, что лучший способ сделать это — показать статус электронного письма в клиентском приложении, чтобы пользователь мог видеть, не удалось ли отправить электронное письмо. . Достаточно ли просто опустить ожидание, или мне следует каким-то образом запустить фонового работника, чтобы отправить электронное письмо?
Что вы можете сделать, так это иметь кнопку «Не получили? Отправить повторно». Почти все приложения, которые я использовал, используют такой подход.
Просто чтобы я понял бизнес-логику. Что происходит, когда сервер электронной почты не работает, что возможно? Означает ли это, что все счета не создаются, поскольку фиксация транзакции зависит от двух действий — создания и отправки по электронной почте? Я думаю, что, возможно, стоит пересмотреть подход к этому, потому что создание счета-фактуры, безусловно, может быть одной функцией, а электронная почта может быть другой, если только вам не обязательно, чтобы эти две функции зависели друг от друга.
В настоящее время, если сервер электронной почты не работает, счета не отправляются. Я буду использовать подход, при котором я запускаю отправку электронной почты в фоновом режиме, а затем обновляю статус счета-фактуры после его отправки. Тогда я просто позволю пользователю увидеть и, возможно, возмутиться в случае неудачи. Спасибо за ваш отзыв! Можете ли вы указать мне ссылку, где я могу увидеть, как запустить такой процесс в .NET Core API? Прямо сейчас у меня есть один фоновый процесс, и это происходит с заданием cron, которое выполняется напрямую, поэтому это не лучший подход.
Это выглядит как идеальный кандидат на шаблон «Исходящие». Если вы считаете, что это стоит дополнительного времени, я бы порекомендовал вам посмотреть его: mbarkt3sto.hashnode.dev/…
В любом случае, как правило, не рекомендуется держать транзакцию открытой так долго. Вместо этого вам нужен сервис Brackground, который извлекает очередь (или из базы данных) и отправляет эти электронные письма.
Никогда не следует просто «пропускать ожидание». Вам необходимо дождаться любых асинхронных вызовов, которые вы делаете, даже если вы не ожидаете их немедленно. Определенно необходимо заставить выполнение электронной почты выполняться в фоновом режиме и вывести ее из транзакции. Есть много способов сделать это. Вы можете сделать это прямо в ASP.NET Core. Или опубликуйте в какой-либо очереди (таблица базы данных, служебная шина Azure, RabbitMQ и т. д.) и поручите другому приложению отвечать за проверку очереди и обработку элементов очереди.
Очереди необходимы для создания масштабируемых и производительных приложений. Вы можете взглянуть на MassTransit, который представляет собой набор .NET-библиотек для прозрачной работы с различными службами шин/очередей, такими как Azure Service Bus, RabbitMQ и Amazon SQS. Доступны и другие варианты, поэтому проведите небольшое исследование, чтобы найти то, что подходит вам лучше всего. Важным моментом является определение узора.
@mason Извините, если это глупый вопрос, но что, если я просто запущу код отправки электронной почты в фоновом режиме? Если я реализую очередь, поможет ли это гарантировать, что отправка не завершится неудачно (какой-то тип политики повторных попыток)? Или сделает так, чтобы потоки не перегружались, если процессов одновременно много? Я просто не уверен, нужно ли мне реализовать очередь для такого случая. Пока мы этим занимаемся, будет ли реализован счетчик «Патерн исходящих сообщений» как наличие очереди, или мне следует поискать какой-то конкретный подход к шине событий? Спасибо за подробное объяснение!
Вы можете запустить его в фоновом режиме без очереди. А как вы предлагаете это реализовать без очереди? Конечно, есть способы сделать это, но очередь — это простой способ сделать это. Шаблон исходящих сообщений, упомянутый vhr, заключается в записи события (необходимости отправки электронного письма) в таблицу БД, а затем публикации этого события в шине сообщений (структурой в этой шине сообщений, скорее всего, будет очередь). По сути, это создает две очереди. Таблица БД, затем очередь в брокере сообщений.





Требует ли ваша бизнес-логика отправки электронного письма в рамках транзакции до того, как объект будет сохранен в базе данных? Я не могу придумать никакой причины, по которой это может быть требованием. Итак, просто отправьте электронное письмо после совершения транзакции. Тогда вы будете точно знать, что ваша транзакция прошла успешно, не беспокоясь об откате.
Большинство функций отправки электронной почты не обязательно должны быть синхронными. Это означает, что вам не нужно ждать успешной отправки электронного письма, прежде чем продолжить. Вместо этого делегируйте функцию отправки электронной почты фоновому заданию. Затем реализуйте механизм обновления статуса после отправки электронного письма.
Бизнес-логика требует, чтобы клиент знал, не удалось ли отправить электронное письмо. Ваше предложение подойдет, потому что я смогу отслеживать статус электронного письма и разрешить пользователю повторно отправить его в случае неудачи. Спасибо за отзыв!
Серверы электронной почты иногда могут медленно отвечать, поэтому лучше всего поставить электронное письмо в очередь для отправки, а затем попросить какого-нибудь фонового работника отправить электронное письмо, но тогда вы снова возвращаетесь к проблеме, заключающейся в том, что вы не можете откатить транзакцию, если она терпит неудачу. Вы уверены, что хотите, чтобы ошибочное электронное письмо отменило транзакцию?