Транспорты Symfony Messenger: ... Заметка
DEV Community на русском

Транспорты Symfony Messenger: Создание транзакционного Outbox поверх

Проблема двойной записи возникает, когда приложение записывает данные в запись базы данных, а затем публикует событие в брокер сообщений, и одна из этих операций завершается неудачно. Это может привести к несоответствиям, когда заказ существует в базе данных, но никакие нижестоящие системы не уведомлены, или наоборот, что вызывает такие проблемы, как "призрачные" заказы и чарджбэки. Паттерн транзакционного аутбокса, реализованный с помощью Symfony Messenger, предлагает надежное решение.Основная идея заключается в том, чтобы вставить событие в таблицу базы данных (аутбокс) в рамках той же транзакции, что и основная запись данных. Это обеспечивает атомарность: запись заказа и запись события либо фиксируются вместе, либо не фиксируются вовсе. Транспорт Doctrine в Symfony Messenger может быть настроен для работы в качестве этой таблицы аутбокса. Направляя события в транспорт Doctrine, операция INSERT для сообщения события включается в существующую транзакцию базы данных.После фиксации транзакции отдельный процесс, обычно messenger:consume, действует как ретранслятор. Этот ретранслятор считывает сообщения из таблицы аутбокса и отправляет их в предполагаемые места назначения, такие как RabbitMQ. Это отделяет отправку событий от обработки первоначального запроса, делая систему устойчивой к сбоям брокера или временным перезапускам. Команда messenger:consume использует SELECT FOR UPDATE SKIP LOCKED, чтобы позволить нескольким рабочим процессам одновременно обрабатывать сообщения из аутбокса без дублирования.Ключевым моментом является то, что паттерн аутбокса гарантирует доставку как минимум один раз, что означает, что обработчики должны быть идемпотентными, чтобы безопасно обрабатывать возможные повторные отправки сообщений. Этого можно достичь, сохраняя стабильный идентификатор события и проверяя таблицу обработанных событий перед выполнением каких-либо побочных эффектов. Направляя события в транспорт Doctrine и используя messenger:consume в качестве ретранслятора, приложения могут обеспечить надежную доставку событий без необходимости использования пользовательской инфраструктуры. Такой подход позволяет сосредоточить инфраструктурные вопросы на периферии, давая возможность домену сосредоточиться на бизнес-логике и облегчая будущие изменения в транспорте сообщений.
CdXz5zHNQW_UmnYYwwYW3.webp