7


5

特定のものの非同期処理にMSMQを使用するアプリケーションがあります。

私はWCFを使用してメッセージをキューに入れ、メッセージを受信して​​処理するためのWCF MSMQリスナー(Windowsサービス)を使用しています。

私の問題はこれを安定させることです。 (たとえば)キューサーバー(別のボックスです)がダウンした場合の対処方法は何ですか? 先日、これが起こり、サービスはそこに座っていました - 例外はスローされず、メッセージの受信を停止しました。 キューサーバがダウンしたときに例外をスローし、それが可能になるまでそれに接続しようとしたいと思います。

また、サービスで「停止」を実行すると、サービスが最終的に停止するまでにかなりの時間ハングすることがよくあります。

どんなコードでも示唆や批判は大歓迎です。 明らかに私はこれのために最初にグーグルをしました、しかし、ほとんどの例は私がすでに持っているものをほとんど私に示しています、そして私は私のシステムをそれより頑強にしたいです。

現在私はこれを持っています:

(注:IMyExampleServiceContractは私のWCFサービス契約であり、QueueHandlerはそれを実装しているものです)

namespace xyz.MyExample.MSMQListener {/// /// WCF MSMQリスナウィンドウサービスの開始と停止を処理するクラス。 /// Windowsサービス管理スナップイン内からの開始および停止コマンドに応答します。 ///パブリック部分クラスMsmqListenerService:ServiceBase {/// /// WCFサービスホスト/// private ServiceHost _serviceHost;

/// /// WCFメッセージの最大サイズを定義します。/// private const long MaxMessageSize = 1024 * 1024 * 1024; // 1 gb /// /// WCF配列の最大サイズを定義します。/// private const int MaxArraySize = 1024 * 1024 * 1024; // 1 GB

/// ///キュー名/// private読み取り専用文字列_queueName; /// ///キューサーバー///プライベート読み取り専用文字列_queueServer;

/// ///クラスの新しいインスタンスを初期化します。 /// public MsmqListenerService(){InitializeComponent();} using(ConfigManager config = new ConfigManager()){_queueName = config.GetAppSetting( "QueueName"); _queueServer = config.GetAppSetting( "QueueServer"); }}

/// ///派生クラスに実装されている場合、サービスコントロールマネージャ(SCM)によってStartコマンドがサービスに送信されたとき、またはオペレーティングシステムが起動したとき(自動的に起動するサービスの場合)に実行されます。 サービス開始時に取るべきアクションを指定します。 /// ///このメソッドのロジックはWCFサービスホストを作成します。 コントラクトを使用してメッセージを待機するもの) /// WCFエンドポイントは、MyExample MSMQサーバー/キューへのNetMSMQBindingです。 ///このエンドポイントを設定し、受信したメッセージを処理するためのクラスを提供します。 /// NetMSMQBindingは、データのMSMQへのシリアル化を処理するMicrosoft WCFバインディングです。 これはms独自のフォーマットであり、キュー///上のメッセージは正しい契約情報を持つWCFサービスによってのみ読み取ることができます。 /// /// /// startコマンドによって渡されたデータ。 OnStart(string [] args){Logger.Write( "MyExample MSMQリスナサービスが開始されました。"、StandardCategories.Information);

Uri serviceUri = new Uri( "net.msmq://" QueueServer QueueName);

NetMsmqBinding serviceBinding = new NetMsmqBinding(); serviceBinding.Security.Transport.MsmqAuthenticationMode = MsmqAuthenticationMode.None; serviceBinding.Security.Transport.MsmqProtectionLevel = System.Net.Security.ProtectionLevel.None; serviceBinding.MaxReceivedMessageSize = MaxMessageSize; serviceBinding.ReaderQuotas.MaxArrayLength = MaxArraySize;

// QueueHandlerはIMyExampleServiceContract _serviceHost = new ServiceHostを実装しています。 _serviceHost.AddServiceEndpoint(typeof(IMyExampleServiceContract)、serviceBinding、serviceUri);

_serviceHost.Open(); Logger.Write( "MyExample MSMQリスナーサービスはOnStartメソッドを完了しました。"、StandardCategories.Information); catch(Exception ex){ExceptionReporting.ReportException(ex、 "DefaultExceptionPolicy");}スロー; }}

/// ///送信先のキューの名前を取得します。 ///これはQueueNameの下のアプリケーション設定から取得されます// //プライベート文字列QueueName {get {return _queueName;} }}

/// ///送信先のキューサーバーの名前を取得します。 ///これは、QueueServerの下のアプリケーション設定から取得されます// //プライベート文字列QueueServer {get {return _queueServer;} }}

/// ///派生クラスに実装されている場合、Service Control Manager(SCM)によってStopコマンドがサービスに送信されたときに実行されます。 サービスの実行が停止したときに実行するアクションを指定します。 /// protected override void OnStop(){if(_serviceHost!= null){_serviceHost.Close();} _serviceHost = null; }}

/// ///アプリケーションのメインエントリポイント。 /// public static void Main(){// Windowsサービスとしてインストールするには、リリースモードでコードをコンパイルする必要があります。 StandardCategories.Information); ServiceBase [] ServicesToRun; ServicesToRun = new ServiceBase [] {new MsmqListenerService()}; ServiceBase.Run(ServicesToRun); Logger.Write( "Finished ServiceBase.キューリスナーサービスの実行"、StandardCategories.Information); catch(Exception e){ExceptionReporting.ReportException(e、 "DefaultExceptionPolicy");}スロー;これにより、ビジュアルスタジオ内から実行することができます。MsmqListenerService service = new MsmqListenerService(); service.OnStart(null); System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite); #endif

}}}

3 Answer


5


サービスホストがハングしている理由はわかりませんが、信頼性を高めるために2つのことが考えられます。

  • サービスホストの Faulted eventに確実にフックしてください。 これは通常、ホストを再起動する必要があることを認識するのに適した場所です。

  • リモートキューサーバーに特別なヘルスステータスキューを用意し、そのキューで2番目のカスタムWCFサービスをリッスンさせることで、サービスが自分自身をpingする方法を設定します。 それから私はサービスホストにただそのキューに定期的にメッセージを送信させて、それをチェックしてもらいたい:

a)それはうまく送信できます

b)メッセージがそのキューで待機しているローカルWCFヘルスサービスによってピックアップおよび処理されていること。 それはいくつかの可能性のあるエラー状態を検出するのに使用することができます。


3


基礎となるWCF MSMQリスナーは、おそらくコードに到達する前に例外をスローしています。 何も起こらず最悪の場合あなたのメッセージがドロップされるように見えるので、これはイライラする状況です。 サービス設定ファイルで WCF service tracingをオンにします。

今あなたがあなたのサービスを実行するとき、それはあなたを追跡しそしてあなたにもっと詳細を与えるでしょう。 XMLを通してあなたの目を圧迫する代わりに、MS Service Trace Viewerでこのログファイルを立ち上げてください。

私がこの問題を抱えていたとき、私は「System.ServiceModel.ProtocolException」を得ていました:

着信MSMQメッセージの本文に無効または予期しない.NETメッセージフレーミング情報が含まれていました。 メッセージを受信できません。 送信者が、一致するSessionMode *と互換性のあるサービス契約を使用していることを確認してください。 私のサービス契約は、属性SessionMode = SessionMode.Requiredを持つように変更されましたが、クライアントはTransactionでメッセージを送信していませんでした。 ___


1


WCFはMSMQにいくつかの優れた機能を追加しますが、手動でMSMQ処理をコーディングすると、同じくらい簡単に、より細かく制御して目標を達成できる場合があります。

手動でキューを処理すると、何が起こっているのかを正確に知ることができます。 QueueNotFoundやMachineNotFoundなどの MessageQueueErrorCodesをキャッチできます。

残念ながら、これは有害メッセージキューの管理、処理へのトランザクションの追加、キューへのタイムアウト期間の追加なども意味します。 WCFがうまく管理しているものすべて。

WCFを使用する主な利点は、Windowsサービスを継続的に実行するのではなく、WASを使用してWebアプリケーションをインスタンス化できることです。 このメリットを利用していないのであれば、WCFにはまったくメリットがありません。タッチして確認する必要があるものを抽象化しているだけです。

 +
ちょっとしたメモとして。おそらく、キューにメッセージを入れているときにサーバーが使用可能かどうかを確認できますか? サーバーがメッセージをキューに書き込むことができる場合は、リスナーはすぐにメッセージを処理できます。