2

これを行うAPIがたくさんあることは知っていますが、ホスティング環境(ASP.NET)では、別のスレッドで確実に実行できることを制限していることも知っています。

私は完全に間違っている可能性があるので、私がそうである場合は私を訂正してください、しかしこれは私が知っていると思うことです。

  • 通常、要求は120秒後にタイムアウトします(これは構成可能です)が、最終的にASP.NETランタイムは、完了するのに時間がかかりすぎる要求を強制終了します。
  • ホスティング環境(通常はIIS)はプロセスのリサイクルを採用しており、いつでもアプリのリサイクルを決定できます。これが発生すると、すべてのスレッドが中止され、アプリが再起動します。しかし、それがどれほど積極的かはわかりません。通常の進行中のHTTPリクエストを中止すると考えるのはちょっとばかげていますが、スレッドの作業単位について何も知らないため、スレッドを中止することを期待します。スレッド。

簡単かつ確実に理論的に長時間実行するタスクを実行するプログラミングモデルを作成する必要がある場合、それは数日間実行する必要がありますが、ASP.NETアプリケーション内からこれをどのように実現しますか?

この問題についての私の考えは次のとおりです。

私は、win32サービスでWCFサービスをホストするという長い道のりを考えてきました。そして、WCFを介してサービスに話しかけます。ただし、これを選択する唯一の理由は、いくつかの異なるWebアプリからタスク(作業単位)を送信することであるため、これはあまり実用的ではありません。その後、最終的にサービスにステータスの更新を依頼し、それに応じて行動します。これに関する私の最大の懸念は、サービスがいくつかの命令を実行できるようにするためにすべてのタスクをサービスにデプロイする必要がある場合、それは特に素晴らしい経験ではないということです。この入力の問題もあります。大きなデータセットがあり、それをかみ砕く必要がある場合、このサービスにデータをどのように提供しますか?

私が今よくしているのはこれです

SELECT TOP 10 * 
FROM WorkItem WITH (ROWLOCK, UPDLOCK, READPAST)
WHERE WorkCompleted IS NULL

これにより、SQL Serverデータベースを作業キューとして使用し、このクエリを使用してデータベースを定期的にポーリングして作業を行うことができます。作業項目が正常に完了した場合、それを完了としてマークし、それ以上何もすることがなくなるまで続行します。私が嫌いなのは、理論的にはいつでも中断される可能性があり、成功と完了のマークの中間にある場合、同じ作業項目を2回処理してしまう可能性があることです。私は少し妄想的かもしれませんし、これはすべて問題ないかもしれませんが、私が理解しているように、それが起こらないという保証はありません...

私は以前にSOについて同様の質問があったことを知っていますが、決定的な答えで実際には答えません。これは非常に一般的なことですが、ASP.NETホスティング環境は長時間実行される作業を処理するための設備が整っていません。

あなたの考えを共有してください。

4

4 に答える 4

5

NServiceBusをご覧ください

NServiceBusは、.NET用のオープンソース通信フレームワークであり、パブリッシュ/サブスクライブおよび長時間実行プロセスのサポートが組み込まれています。

これはMSMQに基づいて構築されたテクノロジーです。つまり、メッセージはディスクに保持されるため、メッセージが失われることはありません。それにもかかわらず、フレームワークは印象的なパフォーマンスと直感的なAPIを備えています。

于 2010-03-25T22:20:43.823 に答える
3

ジョン、

ASP.NETは、あなたが説明したように非同期タスクには適していないことに同意します。また、そうであるべきでもありません。これは、バックオブハウスプロセッサではなく、Webホスティングプラットフォームとして設計されています。

私たちは過去に同様の状況にあり、あなたが説明したものと同様の解決策を使用しました。要約すると、WCFサービスをASP.NETで維持し、Windowsサービスを「QueueProcessor」として使用する「Queue」テーブルを使用します。クライアントは、作業が完了したかどうかを確認するためにポーリングする必要があります(または、メッセージングを使用してクライアントに通知します)。

プロセスとその情報を含むテーブルを使用しました(例:InvoicingRun)。そのテーブルには、ステータス(Pending、Running、Completed、Failed)がありました。クライアントは、ステータスが保留中の新しいInvoicingRunを送信します。Windowsサービス(プロセッサ)はデータベースをポーリングして、保留中の実行を取得します(SQL通知を使用して、ポーリングする必要はありません。保留中の実行が見つかった場合は、実行に移行します。処理を実行してから、完了/失敗に移動します。

プロセスが致命的に失敗した場合(たとえば、DBがダウンした、プロセスが強制終了された場合)、実行は実行状態のままになり、人間の介入が必要になります。プロセスが致命的でない状態(例外、エラー)で失敗した場合、プロセスは失敗に移行し、再試行するか、人間の介入を選択することができます。

複数のプロセッサがあった場合、それを実行状態に移行した最初のプロセッサがそのジョブを取得しました。このメソッドを使用して、ジョブが2回実行されるのを防ぐことができます。別の方法は、選択を実行してから、トランザクションの下で実行するように更新することです。これらのいずれかがトランザクションの大きなトランザクションの外にあることを確認してください。サンプル(大まかな)SQL:

UPDATE InvoicingRun
SET Status = 2 -- Running
WHERE ID = 1
    AND Status = 1 -- Pending

IF @@RowCount = 0
    SELECT Cast(0 as bit)
ELSE
    SELECT Cast(1 as bit)

ロブ

于 2010-03-25T22:18:18.820 に答える
0

カスタム実装の代わりにWorkflowFoundationを使用することを考えましたか?また、状態を永続化することもできます。この場合、タスクはワークフローとして定義できます。

ちょっと考えて...

マイケル

于 2010-03-25T22:07:43.550 に答える
0

Hangfireのような単純なバックグラウンドタスク/ジョブフレームワークを使用し、これらのベストプラクティスの原則を残りのソリューションの設計に適用します。

  • すべてのアクションを可能な限り小さくします。これを達成するために、あなたはすべきです-
  • 長時間実行されるジョブをバッチに分割し、それらをキューに入れます(Hangfireキューまたは別の種類のバスに)
  • 小さなジョブ(長いジョブのバッチ部分)がべき等であることを確認します(任意の順序で実行するために必要なすべてのコンテキストを持っています)。このように、シーケンスを維持するqueteを使用する必要はありません。それならあなたはできるから
  • Webサーバーファームにあるノードの数に応じて、キュー内のジョブの実行を並列化します。これにより、ファームにかかる負荷を制御することもできます(Web要求の処理とのトレードオフとして)。これにより、クラスターがWebクライアントにサービスを提供することを損なうことなく、ジョブ全体(すべてのバッチ)を可能な限り高速かつ効率的に完了することができます。
于 2017-01-19T06:10:57.727 に答える