これを行うための一般的なパターンを 1 つも見つけることができませんでした。しかし、System.Messaging を少し調べてみたところ、Message プロパティと MSMQ の動作を活用することができました。これは、可動部分を最小限に抑えて仕事を完了するための適切な方法だと思います。
これが私が実装したものです。非常にシンプルで軽量であることが判明しました。コードが少なく、保守が簡単です。
次の 3 つのプロパティを持つ RetryLevel というオブジェクトを作成しました。
int Order、int NumberOfRetries、TimeSpan Delay
受信側アプリケーションの構成に、RetryLevel のリストが含まれるようになりました。したがって、新機能は基本的に n レベルの再試行をサポートします。
次に、RetryInfo というオブジェクトを作成しました。このオブジェクトには 2 つのプロパティがあります。
int 試行回数、文字列 SourceQueuePath
RetryInfo オブジェクトのインスタンスがシリアル化され、最終的に再試行される各 Message の Extension プロパティに格納されます。これにより、メッセージ自体の現在の再試行状態を追跡できるため、別の再試行メタデータ ストアを維持する必要がなくなり、メッセージ ID の調整やデータの同期の維持などのすべてのオーバーヘッドがなくなります。
最後に、受信側の構成に待機キュー パスを追加しました。このキューは、「タイムアウト」中にメッセージがドロップされる場所です。
したがって、メッセージ ハンドラーがメッセージを拒否すると、受信者はその RetryInfo がある場合はそれを逆シリアル化し、(以前の) Attempts の数を調べて、設定された RetryLevels のどれに到達したかを判断します。
次に、受信者は Message の TimeToBeRecieved (TTBR) プロパティを DateTime.Now に適切な RetryLevel の Delay 値を加えた値に設定します。次に、AdministrativeQueue プロパティを RetryInfo の SourceQueuePath プロパティから作成されたキューに設定し、メッセージの AcknowledgeType を AcknowledgeTypes.NegativeReceive に設定します。最後に、メッセージを待機キューに入れます。
ここから、MSMQ はメッセージの TTBR を監視します。タイムアウトになると、MSMQ は、メッセージが最初に送信されたキューである AdministrativeQueue プロパティのキューにメッセージを戻します。メッセージがハンドラーによって引き続き拒否された場合、メッセージは RetryLevels を上に移動します。
メッセージの Attempts が、構成された RetryLevels のすべての NumberOfRetries の回数を超える場合、メッセージの TTBR プロパティは TimeSpan.Zero に設定され、UseDeadLetterQueue プロパティは true に設定され、メッセージは他の再試行と同様に待機キューに入れられます。ただし、今回はすぐにタイムアウトになり、MSMQ はそれを待機キューのホストのシステム デッド レター キュー (DLQ) に送り、そこで手動で処理できるようにします。