MVC3 アプリケーションには、永久に実行することを意図した実行時間の長いスレッドがいくつかあります。
ThreadAbortException が他のコード (私のものではない) によって呼び出されているという問題が発生しており、この問題から正常に回復してスレッドを再起動する必要があります。現時点では、appDomain のワーカー プロセスをリサイクルするしかありませんが、これは理想とはほど遠いものです。
このコードの動作に関する詳細は次のとおりです。
この MVC3 アプリケーションには、シングルトン サービス クラスが存在します。データをキャッシュするため、シングルトンでなければなりません。このサービスは、データベースへのリクエストを行います。実際のデータベース接続コードには、サードパーティのライブラリが使用されます。
このシングルトン クラスでは、「QueryRequestors」と呼ばれるクラスのコレクションを使用します。これらのクラスは、データベースへの要求の一意の package+stored_procedure 名を識別して、それらの呼び出しをキューに入れることができるようにします。これが QueryRequestor クラスの目的です。同じ package+stored_procedure への呼び出し (無限に異なるパラメーターがある場合もあります) がキューに入れられ、同時に発生しないようにすることです。これにより、データベースの負担が大幅に軽減され、パフォーマンスが向上します。
QueryRequestor クラスは、内部 BlockingCollection と内部 Task (スレッド) を使用して、そのキュー (ブロッキング コレクション) を監視します。リクエストがシングルトン サービスに入ると、package+stored_procedure 名を介して正しい QueryRequestor クラスを見つけ、そのクラスにクエリを渡します。クエリはキューに入れられます (ブロッキング コレクション)。QueryRequestor の Task は、キューにリクエストがあることを確認し、データベースを呼び出します (現在、サード パーティのライブラリが関与しています)。結果が戻ってくると、シングルトン サービスにキャッシュされます。Task は、ブロッキング コレクションが空になるまで要求の処理を続行し、その後待機します。
QueryRequestor が作成されて実行されると、それが死ぬことは決してありません。このサービスには 24 時間 365 日、数分ごとにリクエストが届きます。サービスのキャッシュにデータがある場合は、それを使用します。データが古くなると、次のリクエストがキューに入れられます (そして、後続の同時リクエストは、誰か (別のスレッド) がキューに入れられたリクエストを既に作成していることを知っているため、キャッシュを使用し続けます。これは効率的です)。
ここでの問題は、QueryRequestor クラス内の Task が ThreadAbortException に遭遇したときに何をすべきかということです。理想的には、そこから回復してスレッドを再開したいと思います。または、少なくとも、QueryRequestor を破棄して (私に関する限り、現在は「壊れた」状態にあります)、最初からやり直してください。package+stored_procedure 名に一致する次のリクエストで、サービスに存在しない場合は新しい QueryRequestor が作成されるためです。
スレッドがサードパーティのライブラリによって強制終了されているのではないかと思いますが、確信が持てません。私が知っているのは、スレッド/タスクを中止したり、強制終了しようとしたりする場所がないということだけです。ずっと走らせたい。しかし、明らかに、この例外のためのコードを用意する必要があります。スレッドが中止されたためにサービスが爆発するのは非常に面倒です。
これを処理する最善の方法は何ですか? どうすればこれを優雅に処理できますか?