Symfony Messenger Transports: ... 노트

Symfony Messenger Transports: 트랜잭션 아웃박스 구축

듀얼 쓰기 문제는 애플리케이션이 데이터베이스 레코드에 데이터를 쓰고 메시지 브로커에 이벤트를 게시한 후 이 작업 중 하나가 실패할 때 발생합니다. 이는 주문이 데이터베이스에 존재하지만 다운스트림 시스템에 알림이 가지 않거나 그 반대의 경우 불일치를 초래하여 유령 주문 및 차지백과 같은 문제를 야기할 수 있습니다. Symfony Messenger가 지원하는 트랜잭셔널 아웃박스 패턴은 강력한 솔루션을 제공합니다.핵심 아이디어는 기본 데이터 쓰기와 동일한 트랜잭션 내에서 이벤트를 데이터베이스 테이블(아웃박스)에 삽입하는 것입니다. 이는 원자성을 보장합니다. 즉, 주문과 이벤트 레코드가 함께 커밋되거나 전혀 커밋되지 않습니다. Symfony Messenger의 Doctrine transport는 이 아웃박스 테이블 역할을 하도록 구성할 수 있습니다. 이벤트를 Doctrine transport로 라우팅함으로써 이벤트 메시지에 대한 INSERT 작업이 기존 데이터베이스 트랜잭션에 포함됩니다.트랜잭션이 커밋된 후, 일반적으로 messenger:consume인 별도의 프로세스가 릴레이 역할을 합니다. 이 릴레이는 아웃박스 테이블에서 메시지를 읽어 RabbitMQ와 같은 의도된 대상으로 디스패치합니다. 이는 이벤트 디스패치를 초기 요청 처리와 분리하여 시스템을 브로커 중단 또는 일시적인 재시작에 대해 복원력 있게 만듭니다. messenger:consume 명령은 SELECT FOR UPDATE SKIP LOCKED를 사용하여 여러 워커가 중복 처리 없이 동시에 아웃박스에서 메시지를 처리할 수 있도록 합니다.중요하게도, 아웃박스 패턴은 최소 한 번의 전달을 보장하므로 핸들러는 잠재적인 메시지 재생을 안전하게 처리하기 위해 멱등성을 가져야 합니다. 이는 안정적인 이벤트 ID를 저장하고 부작용을 실행하기 전에 처리된 이벤트 테이블을 확인하여 달성할 수 있습니다. 이벤트를 Doctrine transport로 라우팅하고 messenger:consume을 릴레이로 사용함으로써 애플리케이션은 사용자 정의 인프라를 요구하지 않고도 안정적인 이벤트 전달을 달성할 수 있습니다. 이 접근 방식은 인프라 문제를 가장자리에 유지하여 도메인이 비즈니스 로직에 집중할 수 있도록 하고 메시지 transport에 대한 향후 변경을 더 쉽게 만듭니다.
CdXz5zHNQW_UmnYYwwYW3.webp