私が説明しようとしているのは、基本的に 2 つの異なるシステム間の 2 フェーズ コミットの問題であり、その処理方法についてアドバイスを求めています。私たちの Web アプリケーションでは、電子メールの送信など、一部の高価な/サードパーティの操作を帯域外のバックグラウンド ワーカー プロセス (ジョブ インフラストラクチャと呼んでいます) にオフロードします。
たとえば、電子メールを送信するには、データベースに電子メール オブジェクトと電子メール ジョブの両方を作成します。次に、ジョブ モニターがメール ジョブを取得して送信するのを待つ必要があります。ジョブ モニターは基本的に、データベースがアイドル状態のときに数秒ごとにデータベースをポーリングすることによって機能します。
ただし、これにより電子メールの送信に遅延が追加され、ポーリングによるデータベースへの過度の負荷と見なされるものが追加されます。電子メールが作成されたらすぐに電子メール ジョブをキューに入れることができれば、さらに便利です。
ただし、これは現在 2 つの理由で失敗しています。まず、キューは多くの場合、Web 要求よりもはるかに高速です。Web 要求がデータベース トランザクションをコミットする前に電子メールが処理のために取得されるため、電子メールを適切に生成できません。次に、Web 要求が失敗すると、データベース トランザクションがロールバックされます。これは、電子メールが送信されないことを意味します。ただし、すでにキューに入れられている場合は、リクエストの制御下にはありません。
キューとデータベースの間で 2 フェーズ コミットを作成するための適切な戦略はありますか? 参考までに、InnoDB テーブルで RabbitMQ と MySQL を使用しています。私が頭に浮かんだアイデアの 1 つは、データベース トランザクションがコミットされた後に電子メール ジョブをキューに保持することでしたが、それでは電子メールがキューに入れられない可能性が残ります。送信されるべきで送信されなかった電子メールを監視するポーリング プロセスを作成する必要があります。