リトライ・コンテキスト内で、Springリスナー・コンテナがトランザクションをどのように処理するかを理解しようとしていました。Springリスナー・コンテナ(トランザクション・マネージャとリトライ・アドバイス・オーダー)
私はこのようなものに構成:
<rabbit:listener-container connection-factory="connectionFactory"
transaction-manager="chainedTransactionManager"
channel-transacted="true"
advice-chain="retryAdvice">
<rabbit:listener ref="myMessageProcessor" queue-names="test.messages" method="handleMessage"/>
</rabbit:listener-container>
をそして私は、トランザクションが再試行の中に含まれることを期待していた、私の取引が何らかの理由で失敗した場合、私は特定の例外を再試行することを決定することができるようにし、他の人には私のDLQにメッセージを送るだけです。
しかし、私は再試行コードがトランザクションコード内に含まれていることに驚いていました。言い換えれば
、春のリスナーがあるようです:
doWithRetry - doIntransaction -> invokeMyCode
私の計画はJpaTransactionManager
とAの両方を含むChainedTransactionManager
を使用していた:
doIntransaction -> doWithRetry -> invokeMyCode
私はそれはこのようになります期待していましたRabbitTransactionManager
ここでは、私が読んだメッセージの承認と、このトランザクション中に送信したメッセージのコミットと特定の条件によってトランザクション全体を再試行することができますが、これはw ay。
だけでなく、トランザクション内で例外が発生した後、コンテキストが役に立たなくなる可能性があります。私は再試行が意味をなさせるために新しい取引が必要です。
また、コミット/ロールバックフェーズで発生した例外は、再試行コンテキスト外で発生するため、再試行されないという問題があります。私は彼らがErrorHandler
の設定に応じて再試行されたと仮定し、私の勧告されたコードに基づいていません。不幸にも、ErrorHandler
にはバックオフポリシーがありません。つまり、トランザクションを再試行した回数をカウントする便利なRetryContext
です。
この場合のように、トランザクションマネージャーでリスナーを構成して機能を再試行するには、どのような方法が推奨されますか?
提案してくれてありがとう、ゲーリー。私はあなたのアイデアをまだ試していませんでした。なぜなら、もう少し気に入っているようなアイデアが出てきたからです。自分の答えを見て、それがあなたに何か意味があるかどうかを見ることができますか?これが問題になるかもしれないと思ったら、私は助言に感謝します。私は一日中、問題の回避策を見つけようと、Spring AMQPコードを読んできました。 –
はい。それはうまくいく - あなたが容器にRabbitTMを必要としなくても、単にローカルに処理されたチャンネルを使うことができる - 我々は依然として 'RabbitTemplate'によって下流使用のためにチャンネルを(デフォルトで)バインドする。再試行が成功した場合、複数の送信がコミットされていることが分かります。 '@RabbitListener'の中で、JPAを処理するための' @ Transactional'ビーンを呼び出し、次に送信を行うことで、明示的なトランザクションテンプレートを避けることができます。 –
こんにちはゲイリー、私はステートフルな再試行を使用すると、トランザクション全体が常に再開され、私の問題を解決すると思います。私はおそらくもっと簡単だと思います。そのため、リスナーでchannelTransactedを実行し、ステートフルなリトライを使用するretryAdviceがそのトリックを行う必要があります。 –