Интеграция RabbitMQ с транзакциями базы данных

Представьте себе ситуацию:

var txn = new DatabaseTransaction();

var entry = txn.Database.Load<Entry>(id);
entry.Token = "123";
txn.Database.Update(entry);

PublishRabbitMqMessage(new EntryUpdatedMessage { ID = entry.ID });

// A bit more of processing

txn.Commit();

Теперь потребитель EntryUpdatedMessage потенциально может получить это сообщение до транзакции txn зафиксировано и, следовательно, не сможет увидеть обновление.

Теперь я знаю, что RabbitMQ поддерживает транзакции сам по себе, но мы не можем их использовать, потому что мы создаем новую IModel для каждой публикации и наличия модели для каждого потока в нашем сценарии действительно сложно (веб-приложение ASP.NET).

Я подумал о том, чтобы иметь список сообщений, которые должны быть опубликованы при фиксации транзакции с БД, но это действительно вонючее решение.

Как правильно справиться с этим?

1 ответ

Решение

RabbitMQ рекомендует вам использовать подтверждения издателя, а не транзакции. Транзакции не работают хорошо.

В любом случае транзакции обычно не очень хорошо работают с сервис-ориентированной архитектурой. Лучше принять "в конечном итоге непротиворечивый" подход, при котором сбой может быть повторен позднее, а дублированные идемпотентные сообщения игнорируются.

В вашем примере я бы сделал обновление базы данных и зафиксировал его перед публикацией сообщения. Когда издатель подтвердит возврат, я обновлю поле в записи базы данных, чтобы указать, что сообщение было отправлено. Затем вы можете запустить процесс очистки, проверить наличие неотправленных сообщений и отправить их по пути. Если сообщение все-таки прошло, но по какой-то причине подтверждение или последующая запись в базу данных не удалось, вы получите дубликат сообщения. Но это не имеет значения, потому что вы создали свои сообщения как идемпотенты.

Другие вопросы по тегам