分散トランザクションがタイムアウトする前にリクエストの処理が終了しない場合、元のメッセージの処理が完了する前、または元のメッセージが処理される前に、同じメッセージが新しいスレッドで再処理される場合、実行時間の長いリクエストを持つメッセージ ハンドラーの問題に気付きました。エラーをスローします。メッセージは最終的にエラー キューに到達します。
問題を再現した方法は次のとおりです。
ローカル マシンの構成を更新して、トランザクションのデフォルト タイムアウトを 1 分に設定しました。
<system.transactions>
<defaultSettings distributedTransactionManagerName="" timeout="00:01:00" />
<machineSettings maxTimeout="00:01:00" />
</system.transactions>
NSB メッセージ サービスをマルチスレッドに設定しました。
<MsmqTransportConfig NumberOfWorkerThreads="2" MaxRetries="2" />
次に、ハンドラーでスレッドを 2 分間スリープさせました (以下のコード)。メッセージがワーカー トレッド A に届きます。1 分間のタイムアウトが発生すると、同じメッセージがワーカー スレッド B で処理され、ワーカー スレッド A は引き続き動作します。睡眠。ワーカー スレッド A が最終的に戻ってきて、「トランザクションに参加できません」というエラーが表示されます。その後、メッセージの処理を再開します。これは、メッセージが最終的にエラー キューに入るまで、両方のワーカー スレッドで続行されます。
public void Handle(RequestDataMessage message)
{
Logger.Info("==========================================================================");
Logger.InfoFormat("Received request {0}.", message.DataId);
Logger.InfoFormat("String received: {0}.", message.String);
Logger.InfoFormat("Header 'Test' = {0}.", message.GetHeader("Test"));
Logger.InfoFormat(Thread.CurrentPrincipal != null ? Thread.CurrentPrincipal.Identity.Name : string.Empty);
var response = Bus.CreateInstance<DataResponseMessage>(m =>
{
m.DataId = message.DataId;
m.String = message.String;
});
response.CopyHeaderFromRequest("Test");
response.SetHeader("1", "1");
response.SetHeader("2", "2");
Thread.Sleep(new TimeSpan(0, 2, 0));
Logger.Info("========== Thread continued ===========");
Logger.InfoFormat("Received request {0}.", message.DataId);
Logger.InfoFormat("String received: {0}.", message.String);
Logger.InfoFormat("Header 'Test' = {0}.", message.GetHeader("Test"));
Logger.InfoFormat(Thread.CurrentPrincipal != null ? Thread.CurrentPrincipal.Identity.Name : string.Empty);
Bus.Reply(response); //Try experimenting with sending multiple responses
}
これは既知の問題ですか、それとも、発生するこの種の集中的な再処理を回避するためにコードを設計する方法はありますか?