【问题标题】:how to avoid any timeout during a long running method execution如何在长时间运行的方法执行期间避免任何超时
【发布时间】:2015-12-30 20:33:26
【问题描述】:

我正在开发一个部署在 IIS-8 中的 asp.net mvc 5 Web 应用程序,我在我的应用程序中有一个方法来执行一项长时间运行的任务,主要扫描我们的网络以查找服务器和虚拟机,并更新我们的数据库扫描结果。方法执行可能会持续 30-40 分钟才能在生产环境中完成。我正在使用一个名为 Hangfire 的计划工具,它每天会调用此方法 2 次。

这里是startup.cs文件里面的job定义,会调用8:01 am&8:01 pm的方法:-

public void Configuration(IAppBuilder app)
{
    var options = new SqlServerStorageOptions
    {
        PrepareSchemaIfNecessary = false
    };
    GlobalConfiguration.Configuration.UseSqlServerStorage("scanservice",options);

    RecurringJob.AddOrUpdate(() => ss.Scan(), "01 8,20 ***");
}

这是调度工具每天调用两次的方法:-

public void Scan()
{
    Service ss = new Service();
    ss.NetworkScan().Wait();
}

最后,进行真正扫描的方法是(我只提供该方法将要做什么的高级描述):-

public async Task<ScanResult> NetworkScan()
{
    // retrieve the server info from the DB
    // loop over all servers & then execute some power shell commands to scan the network & retrieve the info for each server one by one...
    // after the shell command completed for each server, i will update the related server info inside the DB 

目前我在我们的测试环境上做了一些测试,一切都运行良好,扫描大约需要 25 秒来扫描 2 个测试服务器。但现在我们计划将应用程序转移到生产环境中,我们有大约 120++要扫描的服务器。所以我估计方法执行需要大约 30 -40 分钟才能在生产环境中完成。所以我的问题是如何确保此执行永不过期,并且 ScanNetwork() 方法将完成到最后?

【问题讨论】:

  • 不应该在它完成之前运行还是遇到一个导致它提前返回的错误?
  • 为什么担心方法会超时?它应该一直运行到方法完成,或者遇到问题并结束。我不相信一种方法有时间限制。
  • App pool 的默认超时设置为 20 分钟。您可以从您使用的应用程序池的高级设置中更改它。 Windows 服务可能会更好,因此您不必担心它会超时。哎呀,你可以在控制台应用程序中制作它,也可以从任务计划程序运行它。
  • 迪伦是对的。如果您在 Web 服务器上下文中运行类似的东西 - 不要这样做。如果网站必须像这样启动,请创建端点应用程序并从 Web 应用程序启动它。看起来您的网站甚至没有监控反馈。如果您的网站监控您的扫描输出,只需在某处写入更新并让网站定期获取它。或者使用 SignalR 进行反馈
  • 同时增加SqlServerOptions.InvisibilityTimeout(默认为 30 分钟),或者只是更新到 Hangfire 1.5.0(我删除了该超时)以防止其他工作人员在超时后获取相同的后台作业。

标签: asp.net .net asp.net-mvc asp.net-mvc-5 hangfire


【解决方案1】:

也许您可以为每台服务器启动一个新任务,而不用担心您的任务超时。这样,每个任务的生命周期都会很短,并且任何由扫描单个服务器引起的异常都不会影响所有其他任务。此外,如果您的应用程序在 IIS 中重新启动,任何尚未完成的扫描都将恢复。由于所有扫描都发生在一个顺序任务中,这是不可能的。您可能还会看到完成整个网络扫描的总时间直线下降,因为大部分时间可能会花在等待远程服务器上。

public void Scan()
{
    Service ss = new Service();
    foreach (var server in ss.GetServers())
    {
        BackgroundJob.Enqueue<Service>(s => s.ServerScan(server));
    }
}

现在您的计划任务将简单地为每个服务器排队一个新任务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-08
    • 1970-01-01
    • 2015-12-04
    • 2021-12-12
    • 1970-01-01
    • 1970-01-01
    • 2012-06-05
    • 1970-01-01
    相关资源
    最近更新 更多