web-dev-qa-db-ja.com

戻り値とHangfireバックグラウンドジョブ

Task.Run から Hangfire に切り替えています。 .NET 4.5以降では、_Task.Run_は_Task<TResult>_を返すことができます。これにより、void以外を返すタスクを実行できます。通常、プロパティ_MyReturnedTask.Result_にアクセスすることで、タスクの結果を待つことができます。

私の古いコードの例:

_public void MyMainCode()
{
    List<string> listStr = new List<string>();
    listStr.Add("Bob");
    listStr.Add("Kate");
    listStr.Add("Yaz");

    List<Task<string>> listTasks = new List<Task<string>>();

    foreach(string str in listStr)
    {
        Task<string> returnedTask = Task.Run(() => GetMyString(str));
        listTasks.Add(returnedTask);
    }

    foreach(Task<string> task in listTasks)
    {
        // using task.Result will cause the code to wait for the task if not yet finished.
        // Alternatively, you can use Task.WaitAll(listTasks.ToArray()) to wait for all tasks in the list to finish.
        MyTextBox.Text += task.Result + Environment.NewLine;
    }
}
private string GetMyString(string str)
{
    // long execution in order to calculate the returned string
    return str + "_finished";
}
_

Hangfireの Quick Start ページからわかる限り、BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget"));であるメインの人は、バックグラウンドジョブとしてコードを完全に実行しますが、次のようなジョブをサポートしていないようです。戻り値(上記のコードのように)。そうですか?そうでない場合、Hangfireを使用するためにコードを微調整するにはどうすればよいですか?

P.S.私はすでに_HostingEnvironment.QueueBackgroundWorkItem_( ここ )を見ましたが、明らかに同じ機能が欠けています(バックグラウンドジョブはvoidでなければなりません)

[〜#〜]編集[〜#〜]

@Dejanが理解したように、私がHangfireに切り替えたい主な理由は、.NETの人々が.NET4.5.2にQueueBackgroundWorkItemを追加したのと同じ理由です。そして、その理由は、ASP.NETのバックグラウンドタスクに関するScott Hanselmanのすばらしい 記事 に詳しく説明されています。だから私は記事から引用するつもりです:

QBWI(QueueBackgroundWorkItem)は、リクエストに関係なく、バックグラウンドで実行できるタスクをスケジュールします。これは通常のThreadPool作業項目とは異なり、ASP.NETはこのAPIを介して登録された作業項目の数を自動的に追跡し、ASP.NETランタイムはこれらの作業項目の実行が完了するまでAppDomainのシャットダウンを遅らせようとします。

12
yazanpro

簡単な解決策の1つは、次のようにジョブが終了するまで監視APIをポーリングすることです。

_    public static Task Enqueue(Expression<Action> methodCall)
    {
        string jobId = BackgroundJob.Enqueue(methodCall);
        Task checkJobState = Task.Factory.StartNew(() =>
        {
            while (true)
            {
                IMonitoringApi monitoringApi = JobStorage.Current.GetMonitoringApi();
                JobDetailsDto jobDetails = monitoringApi.JobDetails(jobId);
                string currentState = jobDetails.History[0].StateName;
                if (currentState != "Enqueued" && currentState != "Processing")
                {
                    break;
                }
                Thread.Sleep(100); // adjust to a coarse enough value for your scenario
            }
        });
        return checkJobState;
    }
_

注意:もちろん、Webでホストされるシナリオでは、AppDomainがシャットダウンされる可能性があるため、ジョブの終了後にタスク(task.ContinueWith())の継続に依存してさらに多くのことを実行することはできません。ダウン-同じ理由で、おそらく最初にHangfireを使用したいと思うでしょう。

11
Dejan