【问题标题】:Windows scheduler API with console application Vs .net scheduler tools with asp.net mvc to execute long running processes inside my asp.net MVC带有控制台应用程序的 Windows 调度程序 API 与带有 asp.net mvc 的 .net 调度程序工具在我的 asp.net MVC 中执行长时间运行的进程
【发布时间】:2016-06-01 08:21:29
【问题描述】:

我正在开发一个 asp.net mvc-5 Web 应用程序,部署在 windows 2012 和 iis-8 下。我的 asp.net mvc 有许多 CRUD 操作,这些操作在我的 asp.net mvc 中作为操作方法实现。 但是我的 asp.net mvc web 应用程序会进行预定的长时间运行的网络扫描过程,网络扫描主要执行以下步骤:-

  1. 从我们的数据库中获取我们的服务器和虚拟机列表。
  2. 使用 Rest API 从第三方工具获取每个服务器和虚拟机的扫描用户名和密码。
  3. 调用一些 powershell 脚本来检索服务器和虚拟机信息,例如网络信息、内存、名称等。
  4. 使用 Rest API 使用扫描信息更新我们的 ERP 系统。

现在我使用以下方法做了一个试点项目:-

  • 我在我的 asp.net mvc 中定义了一个 Model 方法来执行上述 4 个步骤。
  • 然后我安装 hangfire 工具,它将调用预定义调度程序上的扫描方法。
  • 我还在我的 asp.net mvc 中创建了一个视图,它允许用户设置 hangfire 计划设置(这需要在主机服务器上执行 IIS 重置,以便 hangfire 获取新设置)。

现在我对大约 40 分钟完成的大约 150 台服务器进行了测试扫描,并且运行良好。我唯一注意到的是,如果我将计划设置为在非工作时间运行(在 IIS 上没有进行任何活动),那么 hangfire 将无法调用该作业,并且一旦发出第一个请求,错过的作业将跑步。我通过定义一个每 15 分钟调用一次 IIS 的 Windows 任务来克服这个限制,以保持应用程序池处于活动状态,并且它运行良好...

现在我正在阅读的另一种方法是执行上述操作如下:-

  1. 我可以创建一个单独的控制台应用程序来执行扫描,而不是在 asp.net mvc 中定义 Model 方法来执行扫描。
  2. 然后在我的 asp.net mvc 中创建一个视图,允许用户在 Windows 任务调度程序中创建和调度任务。我可以通过与 Windows 任务调度程序 API 集成来做到这一点。
  3. 此 Windows 任务将在何处调用控制台应用程序。

现在我不确定哪种方法更好,为什么?现在一般来说,长时间运行/后台作业不应该在 iis 下运行。但同时将这些长时间运行的进程定义为控制台应用程序并在 Windows 任务调度程序中调用这些应用程序将在我的 Web 应用程序上创建额外的依赖项。并且在将应用程序从移动服务器移动到另一个服务器时会增加额外的工作量(例如从测试到实时).. 除此之外,我还了解到hangfire、quartz 等工具旨在允许在 IIS 中运行长时间运行的任务,并且它们消除了创建控制台应用程序和使用任务调度程序调度这些控制台应用程序的需要。 那么有人可以就此提出建议吗?

【问题讨论】:

  • 那么如何创建将在您的服务器上运行并通过 WCF 与您的 MVC 应用程序通信的 Windows 本地服务,并在此服务中使用quartz.NET 来安排作业?
  • @Marcin 现在quartz.net 将在iis 下运行,所以我将面临同样的问题,如果我在非工作时间安排长时间运行的进程,那么应用程序池将不会正在运行,所以后台作业不会触发...
  • 看我的回答; Hangfire 建议保持应用程序池始终运行并禁用空闲超时。
  • @john G 为什么quartz.net 会在iis 下运行?您可以创建自己的本地服务,该服务将出现在此处的列表中:%windir%\system32\services.msc,然后您可以从那里运行您的 quartz.net 作业。我正在将此解决方案用于 HID 卡号码同步,并且效果很好。此本地服务通过 WCF 公开一些方法。长话短说:本地服务直接在物理服务器上工作,并与我在 IIS 上运行的 MVC 应用程序进行通信
  • “长时间运行/后台作业不应在 iis 下运行” 正确。 正确的架构是让控制台应用程序扫描您的系统并将您的节点列表写入一个平面文件或数据库,供您的网络应用读取

标签: asp.net asp.net-mvc iis asp.net-mvc-5 console-application


【解决方案1】:
  • 我还在我的 asp.net mvc 中创建了一个视图,它允许用户设置 hangfire 计划设置(这需要在主机服务器上执行 IIS 重置,以便 hangfire 获取新设置)。

您正在重置您的网络服务器以更新任务的日程安排?这听起来不健康。您可能会做的是跟踪计划时间应该,并在执行时检查当前时间是否在计划时间的某个范围内(或已经执行),否则中止工作。

我唯一注意到的是,如果我将计划设置为在非工作时间运行(在 IIS 上不进行任何活动),那么 hangfire 将无法调用该作业,并且一旦发出第一个请求错过的作业将运行。我通过定义一个每 15 分钟调用一次 IIS 的 Windows 任务来克服这个限制,以保持应用程序池处于活动状态,并且它运行良好......

Hangfire 的文档有一个关于 running delayed tasks 的页面,其中提到了您需要更改以适应此情况。

使用 Windows 的任务计划程序似乎不是一个好主意;它不适用于执行临时的、短期的任务。您可能需要提升来创建任务,并且您可能需要定义另一个计划任务来清理在执行了几十个后台作业之后可能存在的大量任务。

您也说得对,使用 Windows 的任务计划程序会使您的应用程序更难移动。

【讨论】:

  • ,,不确定我是否能正确回复您....所以您建议使用哪种方法来运行长时间运行的后台任务..您还提到“使用 Windows 的任务计划程序似乎不像好主意……”你能说出为什么吗?
  • 我的建议是使用 Hangfire,因为它的创建是为了解决您遇到的确切问题(后台工作)。我已经更新了我的答案,以说明 Windows 任务计划程序可能不是一个好主意的原因。
  • 所以你不反对在 IIS 下运行长时间运行和后台进程?因为hangfire(我在我的试点项目中使用的)将在iis下部署?第二个问题,我如何让我的应用程序池保持活动状态,我在其中定义了一个简单的 Windows 任务调度程序,它每 15 分钟运行一次,它调用应用程序,所以我通过这种方式保持我的应用程序池活动......
  • 就像我说的,Hangfire 似乎是为了做你想做的事情而创建的。您使应用程序保持活动状态的方法可行,但更有效的方法是告诉 IIS 不要回收您的应用程序。
  • 现在我遇到了冲突,这导致我提出了这个问题,很多文章提到我们不应该在 iis 下运行长时间运行的处理,因为 iis 旨在处理短请求, ,, 而长时间运行的进程作为控制台应用程序更好,,, 在 windows 任务调度程序下调度,,,
【解决方案2】:

在我看来,如果可以解决Web应用端的调度问题,就没有必要为了触发目的而创建调度任务或新的控制台应用。在 Web 应用程序中使用调度任务时您可能会遇到的问题通常很常见,您可能会看到:调度程序在 Web 应用程序的调试过程中就像一个魅力,但在将其发布到 IIS 后无法触发.此时问题一般与IIS有关,而不是与调度程序Quartz.NETHangfire等有关。虽然网上贴了很多文章或解决方法,但遗憾的是只有一部分能正常工作。除此之外,它们中的大多数都需要在 Web 和机器配置上进行大量配置设置。

不过,对于这种调度问题,也有一些解决方案,我相信值得一试Keep Alive Service For IIS 6.0/7.5。只需将其安装在您发布应用程序的服务器上即可享受。然后您发布的应用程序将在应用程序池回收、IIS/应用程序重新启动等之后仍然存在。这也用于我们的MVC 应用程序,以便每周发送通知邮件,并且已经工作了几个月没有任何问题。这是我在MVC 应用程序中使用的示例代码。欲了解更多信息,请访问Scheduled Tasks In ASP.NET With Quartz.NetQuartz.NET CronTrigger


Global.asax:

protected void Application_Start()
{
    JobScheduler.Start();
}


EmailJob.cs:

using Quartz;

public class EmailJob : IJob
{
    public void Execute(IJobExecutionContext context)
    {
        SendEmail();
    }
}


JobScheduler.cs:

using Quartz;
using Quartz.Impl;

public class JobScheduler
{
    public static void Start()
    {
        IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
        scheduler.Start();

        IJobDetail job = JobBuilder.Create<EmailJob>().Build();
        ITrigger trigger = TriggerBuilder.Create()
            .WithIdentity("trigger1", "group1")
            .StartNow()
            .WithSchedule(CronScheduleBuilder
                .WeeklyOnDayAndHourAndMinute(DayOfWeek.Monday, 10, 00)
                //.WithMisfireHandlingInstructionDoNothing() //Do not fire if the firing is missed
                .WithMisfireHandlingInstructionFireAndProceed() //MISFIRE_INSTRUCTION_FIRE_NOW
                .InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("GTB Standard Time")) //(GMT+02:00)
                )
            .Build();
        scheduler.ScheduleJob(job, trigger);
    }
} 

希望这会有所帮助...

【讨论】:

  • John G 想将此操作分离到控制台应用程序,因为这是长时间的业务操作,而不是因为从 Web 调度的一些问题
  • @Marcin 我只是想处理“...... Vs .net 调度程序工具与 asp.net mvc 在我的 asp.net MVC 中执行长时间运行的进程”他问题的一部分......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-03
  • 2013-06-22
  • 2018-07-29
  • 2016-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多