【问题标题】:Hangfire Background Job with Return Value具有返回值的 Hangfire 后台作业
【发布时间】:2015-05-16 13:08:49
【问题描述】:

我正在从 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(() =&gt; Console.WriteLine("Fire-and-forget")); 完美地将代码作为后台作业运行,但显然不支持具有返回值的作业(如我上面介绍的代码)。那正确吗?如果没有,我该如何调整我的代码以使用 Hangfire?

附:我已经看过HostingEnvironment.QueueBackgroundWorkItem (here) 但它显然缺少相同的功能(后台作业必须是void

编辑

正如@Dejan 发现的那样,我想切换到 Hangfire 的主要原因与 .NET 人员在 .NET 4.5.2 中添加 QueueBackgroundWorkItem 的原因相同。这个原因在 Scott Hanselman 关于 ASP.NET 中的后台任务的精彩 article 中得到了很好的描述。所以我要引用这篇文章:

QBWI (QueueBackgroundWorkItem) 调度一个可以在后台运行的任务,独立于 任何请求。这与普通的 ThreadPool 工作项的不同之处在于 ASP.NET 自动跟踪注册了多少工作项 通过此 API 当前正在运行,并且 ASP.NET 运行时将 尝试延迟 AppDomain 关闭,直到这些工作项目完成 正在执行。

【问题讨论】:

  • 方法的返回值显示在控制面板的作业信息页面上。如果您查看 Hangfire 作业的相关数据库表,则返回值应存储在其中的一个字段中。请参阅github.com/HangfireIO/Hangfire/pull/161 - 除此之外,我不确定是否可以通过编程方式访问它
  • 我有完全相同的问题。在此期间你有什么想法吗?
  • 还没有。您可以随时阅读 Scott Hanselman 关于 ASP.NET 中的后台任务的精彩文章:hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx 我可能很快就会开始赏金,也许我们会得到答案。
  • 请注意,如果您对此感兴趣,Hangfire 1.4.0 引入了continuation 的概念。
  • 您是否使用 Hangfire 来处理您的应用程序中的多线程?如果是这样,您可能使用了错误的工具。

标签: c# asp.net asynchronous hangfire


【解决方案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 托管的场景中,您不能依靠继续执行任务 (task.ContinueWith()) 在作业完成后做更多的事情,因为 AppDomain 可能会被关闭- 出于同样的原因,您可能首先想使用 Hangfire。

【讨论】:

  • 谢谢,关于我改用 Hangfire 原因的最后一句话是完全正确的。
  • 关键是,不可能有涉及返回任务的防弹解决方案。
  • 我使用了相同的代码,但它仍然失败了几次并且大部分时间都通过了。我尝试添加“等待”检查,现在即使没有 Thread.Sleep 也能正常工作。 if (currentState != "Enqueued" && currentState != "Processing" && currentState != "Awaiting")
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-17
  • 1970-01-01
  • 1970-01-01
  • 2020-10-20
  • 2018-08-23
  • 1970-01-01
相关资源
最近更新 更多