87

ASP.Net アプリケーションでは、ユーザーが Web ページのボタンをクリックすると、イベント ハンドラーを通じてサーバー上のオブジェクトがインスタンス化され、オブジェクトのメソッドが呼び出されます。メソッドは外部システムに移動して処理を実行しますが、これには時間がかかる場合があります。だから、私がやりたいのは、そのメソッド呼び出しを別のスレッドで実行して、「あなたの要求が送信されました」というメッセージでユーザーに制御を返すことができるようにすることです。ユーザーがオブジェクトの状態をポーリングし続けることができればさらに良いでしょうが、私はこれをファイア アンド フォーゲットとして行うことにかなり満足しています。

私が知らないのは、ユーザー セッションが期限切れになった場合でも、IIS がスレッドの実行を継続できるかどうかです。ユーザーがイベントを起動し、サーバー上でオブジェクトをインスタンス化し、新しいスレッドでメソッドを起動すると想像してください。ユーザーは「リクエストが送信されました」というメッセージに満足し、ブラウザを閉じます。最終的に、このユーザー セッションは IIS でタイムアウトになりますが、スレッドは引き続き実行され、作業を行っている可能性があります。IIS はスレッドの実行を許可しますか?それとも、ユーザー セッションが期限切れになったら、IIS はスレッドを強制終了してオブジェクトを破棄しますか?

編集:回答とコメントから、これを行う最善の方法は、長時間実行される処理を IIS の外に移動することであると理解しています。他のすべてとは別に、これは appdomain のリサイクルの問題を扱います。実際には、限られた時間内にバージョン 1 を軌道に乗せる必要があり、既存のフレームワーク内で作業する必要があるため、サービス層を避けたいため、IIS 内のスレッドを起動したいだけです。実際には、ここでの「長時間実行」はほんの数分で、Web サイトの同時実行性は低いため、問題ないはずです。ただし、次のバージョンでは、別のサービス レイヤーに分割する必要があります。

4

10 に答える 10

65

あなたはあなたが望むことを達成することができますが、それは通常悪い考えです。いくつかのASP.NETブログおよびCMSエンジンは、共有ホスティングシステムにインストール可能であり、インストールする必要のあるWindowsサービスに依存しないことを望んでいるため、このアプローチを採用しています。通常、アプリの起動時にGlobal.asaxで長時間実行されているスレッドを開始し、そのスレッドプロセスでタスクをキューに入れます。

要求を処理するためにIIS/ASP.NETで使用できるリソースを減らすことに加えて、AppDomainがリサイクルされるときにスレッドが強制終了されるという問題もあります。そのため、実行中のタスクの永続性に対処する必要があります。また、AppDomainが復旧したときに、作業のバックアップを開始します。

多くの場合、AppDomainはデフォルトの間隔で自動的にリサイクルされ、web.configなどを更新した場合も同様です。

スレッドが強制終了される永続性とトランザクションの側面をいつでも処理できる場合は、一定の間隔でサイトにリクエストを送信する外部プロセスを使用することで、AppDomainのリサイクルを回避できます。これにより、サイトがリサイクルされた場合に、 X分以内に自動的に再起動することが保証されています。

繰り返しますが、これは通常悪い考えです。

編集:これが実際のこのテクニックのいくつかの例です:

コミュニティサーバー:Windowsサービスとバックグラウンドスレッドを使用して、スケジュールされた間隔でコードを実行 するWebサイトの最初の起動時にバックグラウンドスレッドを作成する

編集(遠い未来から)-最近はHangfireを使用します。

于 2009-02-11T21:53:01.407 に答える
42

私は受け入れられた答えに同意しません。

Task.Factory.StartNewASP.NETでは、バックグラウンド スレッド (または で始まるタスク) を使用しても問題ありません。すべてのホスティング環境と同様に、シャットダウンを管理する機能を理解し、協力する必要がある場合があります。

ASP.NET では、メソッドを使用して、シャットダウン時に正常に停止する必要がある作業を登録できますHostingEnvironment.RegisterObjectディスカッションについては、この記事とコメントを参照してください。

(Gerard がコメントで指摘しているように、バックグラウンド アイテムが動作するようにスケジューラを登録するHostingEnvironment.QueueBackgroundWorkItemために を呼び出すこともありRegisterObjectます。全体的に、新しいメソッドはタスクベースであるため、より優れています。)

悪い考えだとよく耳にする一般的なテーマについては、Windows サービス (ま​​たは別の種類のプロセス外アプリケーション) を展開する代替案を検討してください。

  • Web デプロイによる簡単なデプロイはもう必要ありません
  • Azure Web サイトだけにデプロイすることはできません
  • バックグラウンド タスクの性質によっては、プロセス間の通信が必要になる可能性があります。つまり、何らかの形式の IPC またはサービスが共通のデータベースにアクセスする必要があります。

また、一部の高度なシナリオでは、要求と同じアドレス空間でバックグラウンド スレッドを実行する必要がある場合もあります。ASP.NET がこれを実現できるという事実は、.NET によって可能になった大きな利点であると私は考えています。

于 2014-09-15T08:43:44.903 に答える
7

このタスクにIISスレッドプールのスレッドを使用すると、そのスレッドが将来の要求を処理できなくなるため、使用しないでください。ASP.NET 2.0で非同期ページを調べることもできますが、それも正しい答えではありません。代わりに、 MicrosoftMessageQueuingを調べることでメリットが得られると思われます。基本的に、タスクの詳細をキューに追加し、別のバックグラウンドプロセス(場合によってはWindowsサービス)がそのタスクの実行を担当します。しかし、肝心なのは、バックグラウンドプロセスがIISから完全に分離されているということです。

于 2009-02-11T16:58:17.077 に答える
7

そのような要件にはHangFireを使用することをお勧めします。そのナイス ファイア アンド フォーゲット エンジンはバックグラウンドで実行され、さまざまなアーキテクチャをサポートし、永続ストレージに支えられているため信頼性があります。

于 2016-02-04T12:40:16.480 に答える
5

私たちはこの道を歩み始めましたが、アプリが 1 つのサーバー上にあるときは実際に問題なく動作しました。複数のマシンにスケール アウトする (または Web ガーデンで複数の w3wp を使用する) 場合、ワーク キュー、エラー処理、再試行、および正しくロックして 1 つだけにするというトリッキーな問題を管理する方法を再評価して検討する必要がありました。サーバーは次のアイテムを取得します。

...バックグラウンド処理エンジンを作成するビジネスではないことに気付いたので、既存のソリューションを探し、素晴らしい OSS プロジェクトhangfireを使用することにしました。

Sergey Odinokov は、作業を永続化してキューに入れる方法のバックエンドを交換できる、非常に簡単に開始できる本物の gem を作成しました。Hangfire はバックグラウンド スレッドを使用しますが、ジョブを永続化し、再試行を処理し、ワーク キューを可視化します。そのため、hangfire ジョブは堅牢であり、リサイクルされるアプリドメインなどのすべての気まぐれに耐えます。

その基本的なセットアップではストレージとして sql サーバーを使用しますが、スケールアップするときに Redis または MSMQ に交換できます。また、すべてのジョブとそのステータスを視覚化するための優れた UI を備えており、ジョブを再キューイングすることもできます。

私が言いたいのは、バックグラウンド スレッドでやりたいことを完全に実行できる一方で、スケーラブルで堅牢にするために多くの作業が必要だということです。単純なワークロードには問題ありませんが、物事がより複雑になると、この作業を行うよりも専用のライブラリを使用することを好みます。

利用可能なオプションの詳細については、asp.net でバックグラウンド ジョブを処理するためのいくつかのオプションについて説明している Scott Hanselman のブログを参照してください。(彼はハングファイアに熱烈なレビューを与えました)

また、ジョンが参照しているように、このアプローチに問題がある理由と、appdomain がアンロードされたときにスレッドでの作業を適切に停止する方法について、Phil Haack のブログを読む価値があります。

于 2014-11-06T03:11:51.237 に答える
5

ここに良いスレッドとサンプル コードがあります: http://forums.asp.net/t/1534903.aspx?PageIndex=2

アプリ プールを維持するために、スレッドから Web サイトのキープ アライブ ページを呼び出すというアイデアも試しました。この方法を使用する場合は、アプリケーションがいつでもリサイクルされる可能性があるため、適切な回復処理が必要であることに注意してください。多くの人が言及しているように、他のサービスオプションにアクセスできる場合、これは正しいアプローチではありませんが、共有ホスティングの場合、これは唯一のオプションの1つになる可能性があります.

アプリ プールを維持するために、スレッドの処理中に自分のサイトにリクエストを送信できます。これは、プロセスが長時間実行されている場合にアプリ プールを維持するのに役立つ場合があります。

string tempStr = GetUrlPageSource("http://www.mysite.com/keepalive.aspx");


    public static string GetUrlPageSource(string url)
    {
        string returnString = "";

        try
        {
            Uri uri = new Uri(url);
            if (uri.Scheme == Uri.UriSchemeHttp)
            {
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
                CookieContainer cookieJar = new CookieContainer();

                req.CookieContainer = cookieJar;

                //set the request timeout to 60 seconds
                req.Timeout = 60000;
                req.UserAgent = "MyAgent";

                //we do not want to request a persistent connection
                req.KeepAlive = false;

                HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
                Stream stream = resp.GetResponseStream();
                StreamReader sr = new StreamReader(stream);

                returnString = sr.ReadToEnd();

                sr.Close();
                stream.Close();
                resp.Close();
            }
        }
        catch
        {
            returnString = "";
        }

        return returnString;
    }
于 2011-01-12T20:05:12.790 に答える
2

そのタスクを実行するための Windows サービスを作成できますか? 次に、Web サーバーから .NET リモート処理を使用して、Windows サービスを呼び出してアクションを実行しますか? もしそうなら、それは私がすることです。

これにより、IIS でリレーする必要がなくなり、処理能力の一部が制限されます。

そうでない場合は、プロセスが完了するまでユーザーをそこに座らせます。そうすれば、IIS によって強制終了されずに完了することが保証されます。

于 2009-02-11T21:57:18.493 に答える
2

タスクはバックグラウンドで実行でき、リクエストが終了した後でも完了します。キャッチされない例外がスローされないようにします。通常、常に例外をスローする必要があります。新しいスレッドで例外がスローされると、要求のコンテキストに存在しなくなるため、 IIS ワーカー プロセス ( w3wp.exe ) がクラッシュします。また、インプロセス メモリ バックグラウンド セッションを使用している場合は、それに加えて、実行している他のバックグラウンド タスクも強制終了します。これを診断するのは難しいため、この方法はお勧めできません。

于 2016-10-27T03:21:52.937 に答える
2

IIS で長時間実行される作業をホストする方法が 1 つサポートされているようです。 ワークフロー サービスは、特にWindows Server AppFabricと組み合わせて、このために設計されているようです。この設計では、長時間実行される作業の自動永続化と再開をサポートすることで、アプリケーション プールのリサイクルが可能になります。

于 2012-10-05T15:19:18.757 に答える
1

非同期タスクを実行する代理プロセスを作成するだけです。Windows サービスである必要はありません (ただし、ほとんどの場合、それがより最適なアプローチです。MSMQ は、殺しすぎです。

于 2009-02-13T13:21:55.050 に答える