web-dev-qa-db-ja.com

Web Api-火と忘れ

Web APIのアクションがあるため、タスクを実行し、このタスクを忘れる必要があります。これが私の方法の構成方法です。

public async Task<SomeType> DoSth()
{
    await Task.Run(...);
    .....
    //Do some other work
}

問題は、明らかに、それが完了すると待機ラインで停止し、その後のみ作業を続行することです。そして、「発火して忘れる」必要があります。非同期待機なしでTask.Run()を呼び出すだけですか?

26
D. Jones

そして、「発射して忘れる」必要があります

ASP.NETのfire-and-forget のいくつかの異なるアプローチの詳細を説明するブログ投稿があります。

要約すると、まず、火事を忘れないようにしてください。それはほとんど常に悪い考えです。あなたは本当に「忘れる」ことを望みますか?のように、正常に完了するかどうかは気にしませんか?エラーを無視しますか?ログ通知なしで時折「仕事を失った」を受け入れますか?ほとんどの場合、答えは「いいえ」で、「火と忘れ」は適切なアプローチではありません。

信頼できるソリューションは、適切な分散アーキテクチャを構築することです。つまり、実行する作業を表すメッセージを作成し、そのメッセージを信頼できるキュー(Azure Queue、MSMQなど)にキューイングします。次に、そのキューを処理する独立したバックエンド(Azure WebJob、Win32サービスなど)を用意します。

Async-awaitなしでTask.Run()を呼び出す必要がありますか?

いいえ。これは最悪の解決策です。あなたがmustしなければならない場合、分散アーキテクチャを構築したくない場合は、Hangfireを検討してください。それがうまくいかない場合は、veryで少なくともHostingEnvironment.QueueBackgroundWorkItemまたはmy経由でASP.NETランタイムにカウボーイのバックグラウンドワークを登録する必要があります。 ASP.NETバックグラウンドタスクライブラリ 。 QBWIとAspNetBackgroundTasksはどちらも信頼性の低いソリューションであることに注意してください。彼らはちょうど最小化、あなたが仕事を失う可能性を、ない防止それ。

24
Stephen Cleary

Asp.netでは、タスクの一部として作成されたリクエストとともに頻繁に死ぬことがあるため、真の発射タスクと忘却タスクは困難な場合があります。

4.5.2+を使用している場合は、 QueueBackgroundWorkItem を使用してタスクを実行できます。このメソッドを介してタスクを登録することにより、AppDomainはtryを実行し、すべて完了するまでシャットダウンを遅らせますが、それらが完了する前に強制終了される場合があります完了しました。これはおそらく最も簡単なことですが、どのインスタンスがジョブをキャンセルする可能性があるかを正確に確認する価値があります。

HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken =>
{
  await Task.Run(...);
});

hangfire というツールがあり、永続ストアを使用して、タスクが完了し、組み込みの再試行およびエラー記録機能を備えていることを確認します。これは「バックグラウンドタスク」に適していますが、火事や忘れに適しています。これは比較的簡単に設定でき、さまざまなバッキングストアを提供します。正確な詳細は思い出せませんが、ライセンスが必要なものとそうでないもの(MSSQLなど)があります。

7
Fermin

火と忘れて、これを使用してください

Task.Factory.StartNew(async () =>
{
    using (HttpClient client = new HttpClient())
    {
        await client.PostAsync("http://localhost/api/action", new StringContent(""));
    }
});
6
Catalin

HangFire を使用します。

これは私に最適です。

.NETおよび.NET Coreアプリケーションでバックグラウンド処理を実行する簡単な方法。 Windowsサービスまたは別のプロセスは必要ありません。

永続的なストレージに支えられています。オープンで無料で商用利用できます。

3
Majid gharaei

起動して忘れないでください。エラーが表示されないため、何か問題が発生した場合に非常に厄介なトラブルシューティングが行われます(タスクメソッドが独自の例外処理を行うことは、タスクが動作しない可能性があるため保証されません最初から正常に起動します)。あなたが本当にでない限り、タスクが何かをするかどうかは気にしませんが、それは非常に珍しいことです(本当に気にしないなら、なぜ実行するのかそもそもタスク?)?少なくとも、 継続 でタスクを作成します。

_Task.Run(...)
  .ContinueWith(t => 
    logException(t.Exception.GetBaseException()),
    TaskContinuationOptions.OnlyOnFaulted
  )
;
_

ニーズに応じて、これをより洗練させることができます。

Web APIの特定のケースでは、リクエストを完了する前に、バックグラウンドタスクが完了するのを実際に待つことができます。そうしないと、サービスが実際にどれだけの負荷をかけることができるかを誤って伝える可能性のあるものをバックグラウンドで実行したままにするか、クライアントがあまりにも多くのリクエストを発行し、それらを調整するために何もしなければ、動作を完全に停止します。タスクを収集し、最後にawait Task.WhenAll(...)を発行してそれを達成できます。このようにして、バックグラウンドタスクが終了するまで有用な作業を続けることができますが、すべてが完了するまで戻りません。

2
Jeroen Mostert

Fireを呼び出してWebApiメソッドを忘れるには、次のコードを使用しましたOK応答が返されるようにするため。私の場合、ログイン時に作成されたベアラー認証トークンはCookieに保存されます。

...
FireAndForget().Wait();
...

private async Task FireAndForget()
    {
        using (var httpClient = new HttpClient())
        {
            HttpCookie cookie = this.Request.Cookies["AuthCookieName"];
            var authToken = cookie["AuthTokenPropertyName"] as string;
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
            using (var response = await httpClient.GetAsync("http://localhost/api/FireAndForgetApiMethodName"))
            {
                //will throw an exception if not successful
                response.EnsureSuccessStatusCode();
            }
        }
    }
1
CAK2

私はあなたがあなたの電話をただ忘れてはならないことを他の人に同意します。ただし、質問に答えるために、Task.Run()行からawaitを削除した場合、 here のように呼び出しはブロックされません。

public async Task<SomeType> DoSth()
{
    Task.Run(...);
    .....
    //Do some other work while Task.Run() continues in parallel.
}
0
Avinash Kumar

ここにはいくつかの投稿があり、「絶対に火をつけずに忘れる」、その間違いなどをプッシュします。

真実は、特定の観点からは間違っていません。むしろいくつかの点で誤って説明されています。

これが本当に言うべきことは、「ユーザーは発火して忘れることができるはずですが、それでも開発者/所有者に伝える必要があります。」

良い例は、ウェブサイト上のお問い合わせフォームです。顧客はフォームに入力し、舞台裏でサイトの所有者にメールを送信します。一部のメールサーバーは送信処理に時間がかかるため、Hangfireなどのパッケージ(これを使用します)は、Webサーバーの「スレッド」外の別のプロセスに送信します。

はい、エラーが発生した場合、何らかの方法で開発者/所有者に通知する必要があります(連絡先の詳細を保持します)。しかし、これにより問題について潜在的な連絡先に通知されることはありません。 (潜在的な顧客を失いたくない場合)

0