17

WCFサービスを作成し、netMsmqBindingバインディングを利用しています。

これは、Dtoをサービスメソッドに渡し、応答を期待しない単純なサービスです。メッセージはMSMQに配置され、ピックアップされるとデータベースに挿入されます。

データが失われていないことを確認するための最良の方法は何ですか。

私は次の2つの方法を試しました。

  1. 例外をスローする

    これにより、メッセージは手動で閲覧できるようにデッドレターキューに入れられます。私のstrviceが始まるときにこれを処理することができます

  2. バインディングにreceiveRetryCount="3"を設定します

    3回試行した後-これは瞬時に発生しますが、これはメッセージをキューに残しているようですが、私のサービスに障害があります。サービスを再起動すると、このプロセスが繰り返されます。

理想的には、次のことを行いたいと思います。

メッセージを処理してみてください

  • これが失敗した場合は、そのメッセージを5分間待ってから、再試行してください。
  • そのプロセスが3回失敗した場合は、メッセージをデッドレターキューに移動します。
  • サービスを再起動すると、デッドレターキューからのすべてのメッセージがキューに戻され、処理できるようになります。

これを達成できますか?もしそうなら、どのように?特定のシーンでWCFとMSMQを最適に利用する方法に関する優れた記事を教えてください。

どんな助けでも大歓迎です。ありがとう!

いくつかの追加情報

WindowsXPおよびWindowsServer2003でMSMQ3.0を使用しています。残念ながら、MSMQ4.0およびVista/2008を対象とした組み込みのポイズンメッセージサポートを使用できません。

4

4 に答える 4

14

MSMQ (Vista でのみ利用可能) を使用すると、次のようにできると思います。

<bindings>
    <netMsmqBinding>
        <binding name="PosionMessageHandling"
             receiveRetryCount="3"
             retryCycleDelay="00:05:00"
             maxRetryCycles="3"
             receiveErrorHandling="Move" />
    </netMsmqBinding>
</bindings>

WCF は、最初の呼び出しが失敗した後、すぐに ReceiveRetryCount 回再試行します。バッチが失敗した後、メッセージは再試行キューに移動されます。RetryCycleDelay 分の遅延の後、メッセージは再試行キューからエンドポイント キューに移動し、バッチが再試行されます。これは MaxRetryCycle 時間繰り返されます。すべてが失敗した場合、メッセージは receiveErrorHandling に従って処理されます。これは (ポイズン キューに) 移動、拒否、ドロップ、またはフォールトできます。

ところで、WCF と MSMQ に関する優れたテキストは、Juval Lowy の Progammig WCF book の第 9 章です。

于 2008-09-17T12:29:41.833 に答える
9

あなたの場合に役立つかもしれない SDK のサンプルがあります。基本的には、IErrorHandler 実装をサービスにアタッチして、WCF がメッセージを「毒」と宣言したとき (つまり、構成されたすべての再試行が使い果たされたとき) にエラーをキャッチします。サンプルが行うことは、メッセージを別のキューに移動してから、メッセージに関連付けられた ServiceHost を再起動することです (有害なメッセージが見つかったときにエラーが発生するため)。

これはあまりきれいなサンプルではありませんが、役に立つ可能性があります。ただし、いくつかの制限があります。

1- サービスに複数のエンドポイントが関連付けられている (つまり、複数のキューを介して公開されている) 場合、有害なメッセージがどのキューに到着したかを知る方法はありません。キューが 1 つしかない場合、これは問題になりません。これに対する公式の回避策は見たことがありませんが、ここに文書化した代替案を試してみました: http://winterdom.com/weblog/2008/05/27/NetMSMQAndPoisonMessages.aspx

2- 問題のメッセージが別のキューに移動されると、それはあなたの責任になるため、タイムアウトが完了したら、それを処理キューに戻す (またはそれを処理するためにそのキューに新しいサービスをアタッチする) のはあなた次第です。

正直に言うと、どちらの場合も、WCF だけでは対応していない "手作業" の作業が見られます。

私は最近、再試行の頻度を明示的に制御する必要がある別のプロジェクトに取り組んでおり、現在の解決策は、再試行キューのセットを作成し、再試行キューとメイン処理キューの間でメッセージを手動で移動することでした。生の System.Messaging を使用して MSMQ キューを処理するだけです。このようにすると、いくつかの落とし穴がありますが、かなりうまく機能しているようです。

于 2008-09-17T17:36:23.077 に答える
4

SQL-Server を使用している場合は、MSMQ と SQL-Server の両方がサポートしているため、分散トランザクションを使用する必要があります。データベースの書き込みを TransactionScope ブロックでラップし、成功した場合にのみ scope.Complete() を呼び出します。失敗した場合、WCF メソッドが返されると、メッセージはキューに戻されて再試行されます。私が使用するコードのトリミングされたバージョンは次のとおりです。

    [OperationBehavior(TransactionScopeRequired=true, TransactionAutoComplete=true)]
    public void InsertRecord(RecordType record)
    {
        try
        {
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
            {
                SqlConnection InsertConnection = new SqlConnection(ConnectionString);
                InsertConnection.Open();

                // Insert statements go here

                InsertConnection.Close();

                // Vote to commit the transaction if there were no failures
                scope.Complete();
            }
        }
        catch (Exception ex)
        {
            logger.WarnException(string.Format("Distributed transaction failure for {0}", 
                Transaction.Current.TransactionInformation.DistributedIdentifier.ToString()),
                ex);
        }
     }

これをテストするには、多数の既知のレコードをキューに入れ、WCF に多数のスレッドを開始させて、それらの多くを同時に処理させ (16 スレッドに到達し、一度に 16 メッセージがキューから削除されます)、操作の途中でプロセスを強制終了します。 . プログラムが再起動されると、メッセージはキューから読み戻され、何も起こらなかったかのように再度処理されます。テストの最後には、データベースに一貫性があり、失われたレコードはありません。

分散トランザクション マネージャーにはアンビエント プレゼンスがあり、TransactionScope の新しいインスタンスを作成すると、メソッド呼び出しのスコープ内で現在のトランザクションが自動的に検索されます。これは、WCF がメッセージをキューからポップしたときに既に作成されているはずです。メソッドを呼び出しました。

于 2008-09-17T12:54:14.520 に答える
1

残念ながら、私は Windows XP と Windows Server 2003 で行き詰まっているので、それは私にとって選択肢ではありません。- (投稿後にこの解決策を見つけ、使用できないことに気付いたので、質問で再確認します)

解決策の 1 つは、メッセージを別のキューまたはポイズン キューに移動し、サービスを再起動するカスタム ハンドラーをセットアップすることであることがわかりました。これは私にはクレイジーに思えました。私の SQL Server がダウンしていて、サービスが再起動される頻度を想像してみてください。

だから私がやったことは、ラインが失敗してキューにメッセージを残すことを可能にすることです。また、これが発生したという致命的なメッセージをシステム ログ サービスに記録します。問題が解決したら、サービスを再起動すると、すべてのメッセージが再び処理され始めます。

このメッセージまたは他のメッセージの再処理はすべて失敗することに気付きました。なぜこのメッセージと他のメッセージを別のキューに移動する必要があるのでしょうか。サービスを停止し、すべてが期待どおりに動作しているときに再開することもできます。

aogan さん、あなたは MSMQ 4.0 に対して完璧な答えを持っていましたが、残念ながら私にとってはそうではありませんでした

于 2008-09-17T12:43:24.017 に答える