То, что я собираюсь описать, - это, по сути, проблема двухфазной фиксации между двумя несопоставимыми системами, и я ищу совет о том, как ее решить. В нашем веб-приложении мы перекладываем некоторые дорогостоящие / сторонние операции, такие как отправка электронных писем, на внешние фоновые рабочие процессы (мы называем это нашей инфраструктурой работы).
Например, чтобы отправить электронное письмо, мы создаем в нашей базе данных как объект электронной почты, так и задание электронной почты. Затем мы должны подождать, пока наш монитор работы заберет работу по электронной почте и отправит ее. Монитор заданий по существу работает, опрашивая базу данных каждые несколько секунд, когда она простаивает.
Это, однако, добавляет задержку при отправке электронной почты и добавляет то, что я считаю чрезмерной нагрузкой на базу данных при опросе. Было бы гораздо приятнее, если бы мы сразу же поместили задание электронной почты в очередь, как только оно будет создано.
Однако в настоящее время это не удается по двум причинам. Во-первых, очередь часто намного быстрее, чем веб-запрос. Электронная почта забирается для обработки до того, как веб-запрос совершил транзакцию базы данных, поэтому она не может правильно сгенерировать электронную почту. Во-вторых, если веб-запрос завершается неудачно, он откатывает свою транзакцию базы данных, что означает, что электронное письмо должно не быть отправлено. Однако, если он уже помещен в очередь, он больше не находится под контролем запроса.
Есть ли хорошая стратегия для создания двухфазного коммита между очередью и базой данных? Для справки мы используем RabbitMQ и MySQL с таблицами InnoDB. Одна идея, которую я возглавил, заключалась в том, чтобы помещать задания электронной почты в очередь после совершения транзакции с базой данных, но при этом остается вероятность того, что электронное письмо никогда не попадет в очередь. Мне все еще придется создать процесс опроса, который отслеживает электронные письма, которые должны были быть отправлены, а не отправлены.