コンポーネントをデプロイするたびに、次の例外を受け取りました。コンポーネント自体が開始されないこともあれば、サービス コンソールが開始済みと表示されることもありますが、サービスはメッセージを処理しません。エラーは非常に簡単です。まだプレフィックスをリッスンしている別の HttpListener があります。
NServiceBus.Hosting.GenericHost System.Exception: Failed to start listener for http://localhost/products/ make sure that you have admin priviliges ---> System.Net.HttpListenerException: Failed to listen on prefix 'http://localhost:80/products/' because it conflicts with an existing registration on the machine.
at System.Net.HttpListener.AddAllPrefixes()
at System.Net.HttpListener.Start()
at NServiceBus.Gateway.Channels.Http.HttpChannelReceiver.Start(String address, Int32 numWorkerThreads) in c:\BuildAgent\work\nsb.master_6\src\gateway\NServiceBus.Gateway\Channels\Http\HttpChannelReceiver.cs:line 30
--- End of inner exception stack trace ---
at NServiceBus.Gateway.Channels.Http.HttpChannelReceiver.Start(String address, Int32 numWorkerThreads) in c:\BuildAgent\work\nsb.master_6\src\gateway\NServiceBus.Gateway\Channels\Http\HttpChannelReceiver.cs:line 37
at NServiceBus.Gateway.Receiving.GatewayReceiver.Start(Address localAddress) in c:\BuildAgent\work\nsb.master_6\src\gateway\NServiceBus.Gateway\Receiving\GatewayReceiver.cs:line 38
at System.Collections.Generic.List`1.ForEach(Action`1 action)
at NServiceBus.Unicast.UnicastBus.NServiceBus.IStartableBus.Start(Action startupAction) in c:\BuildAgent\work\nsb.master_6\src\unicast\NServiceBus.Unicast\UnicastBus.cs:line 867
at NServiceBus.Hosting.GenericHost.Start() in c:\BuildAgent\work\nsb.master_6\src\hosting\NServiceBus.Hosting\GenericHost.cs:line 34
深い分析を行うとき。
- この問題は、NServiceBus.Master プロファイルを実行している場合にのみ発生します
- この問題は、サービス コンソールから実行サービスを再起動するたびにのみ発生します
- 実行する WorkerThreads の数に関係ありません
NSB コードをさらに深く読むと、オブジェクトの Dispose 中に HttpListener が閉じられていることがわかりました。これに加えて、サービスを停止すると、プロセス自体が強制終了されるため、指定された URL プレフィックスをリッスンするオブジェクトがマシン上に存在しなくなります。しかし、私たちは間違っていました。多くの閉鎖を分析したところ、Service-Console がサービスが停止したと見なした後でも、NServinceBus.Host プロセスがまだ実行されていることがわかりました。サービス コンソールでサービスを停止するたびに、プロセスはマシン上でまだアクティブであり、完全にシャットダウンするのにかなりの時間がかかりました。そのため、再起動を実行すると、現在のサービスのプロセスのインスタンスが複数存在する可能性があります。1 つが開始しようとしていて、別のインスタンスがまだ停止しようとしています。再起動プロセスで上記の例外がスローされることを確認しました。
シャットダウンしていたプロセスのダンプを取得しました。サービス コンソールでステータスが停止と表示されていても、バックグラウンド スレッドがまだプロセス上でアクティブであることがわかりました。破棄中にロック/ObjWait が大量に発生します。停止したサービスがまだ HttpListener オブジェクトを閉じていないことを確認してください。
Child SP IP Call Site
000000001f19e048 00000000778818ca [GCFrame: 000000001f19e048]
000000001f19e118 00000000778818ca [HelperMethodFrame_1OBJ: 000000001f19e118] System.Threading.Monitor.ObjWait(Boolean, Int32, System.Object)
000000001f19e230 000007fe99d57ccb System.Transactions.CommittableTransaction.Commit()
000000001f19e2d0 000007fe99d577df System.Transactions.TransactionScope.InternalDispose()
000000001f19e3c0 000007fe99d56f1c System.Transactions.TransactionScope.Dispose()
000000001f19e590 000007fe99c4a3b5 NServiceBus.Utils.TransactionWrapper.RunInTransaction(System.Action, System.Transactions.IsolationLevel, System.TimeSpan)
000000001f19e610 000007fe99c45b2b NServiceBus.Unicast.Transport.Transactional.TransactionalTransport.Process()
000000001f19e680 000007fe99c455cb NServiceBus.Utils.WorkerThread.Loop()
000000001f19e6d0 000007fef6fdf8a5 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
000000001f19e830 000007fef6fdf609 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
000000001f19e860 000007fef6fdf5c7 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
000000001f19e8b0 000007fef6ff2d21 System.Threading.ThreadHelper.ThreadStart()
000000001f19ebc8 000007fef81cf713 [GCFrame: 000000001f19ebc8]
000000001f19eef8 000007fef81cf713 [DebuggerU2MCatchHandlerFrame: 000000001f19eef8]
000000001f19f0d8 000007fef81cf713 [ContextTransitionFrame: 000000001f19f0d8]
000000001f19f2c8 000007fef81cf713 [DebuggerU2MCatchHandlerFrame: 000000001f19f2c8]
HttpListener がアクティブでリッスンしていることがわかりました。
Child SP IP Call Site
000000002038e2f8 000000007788135a [InlinedCallFrame: 000000002038e2f8] System.Net.UnsafeNclNativeMethods+HttpApi.HttpReceiveHttpRequest(System.Runtime.InteropServices.CriticalHandle, UInt64, UInt32, HTTP_REQUEST*, UInt32, UInt32*, System.Threading.NativeOverlapped*)
000000002038e2f8 000007fe99c6a2f8 [InlinedCallFrame: 000000002038e2f8] System.Net.UnsafeNclNativeMethods+HttpApi.HttpReceiveHttpRequest(System.Runtime.InteropServices.CriticalHandle, UInt64, UInt32, HTTP_REQUEST*, UInt32, UInt32*, System.Threading.NativeOverlapped*)
000000002038e2b0 000007fe99c6a2f8 DomainBoundILStubClass.IL_STUB_PInvoke(System.Runtime.InteropServices.CriticalHandle, UInt64, UInt32, HTTP_REQUEST*, UInt32, UInt32*, System.Threading.NativeOverlapped*)
000000002038e3b0 000007fe99c697a4 System.Net.HttpListener.GetContext()
000000002038e4d0 000007fe99c6924f NServiceBus.Gateway.Channels.Http.HttpChannelReceiver.HttpServer()
000000002038e530 000007fef6fdf8a5 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
000000002038e690 000007fef6fdf609 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
000000002038e6c0 000007fef6fdf5c7 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
000000002038e710 000007fef6ff2d21 System.Threading.ThreadHelper.ThreadStart()
000000002038ea28 000007fef81cf713 [GCFrame: 000000002038ea28]
000000002038ed58 000007fef81cf713 [DebuggerU2MCatchHandlerFrame: 000000002038ed58]
000000002038ef38 000007fef81cf713 [ContextTransitionFrame: 000000002038ef38]
000000002038f128 000007fef81cf713 [DebuggerU2MCatchHandlerFrame: 000000002038f128]
質問: プロセスがまだマシン上でアクティブであるにもかかわらず、サービス コンソールがサービスが停止していると報告するのはなぜですか
注:この問題を再現するには、NServiceBus.Master プロファイルを使用してホストを Windows サービスとしてインストールし、サービスの再起動を試行する必要があります。この問題を解決するには、さらに試行が必要になる場合があります。
アップデート:
HttpChannelReceiver.Start() で NSB コードを読むと、新しいスレッドでリスナーが開始されます。
- このリスナー スレッドはフォアグラウンド スレッドです。(他のすべてのワーカー スレッドは BG スレッドです)
- このフォアグラウンド スレッドに停止信号は送信されません
- このスレッドの参照を保持する変数/フィールドはありません。中止はできません。
このリスナー スレッドは、ServiceHost が現在のプロセスのメモリを強制終了したときにのみ再利用されます。ServicHost がそれを収集するまで、このスレッドは現在のプロセスを終了できません。