【问题标题】:Best way to run scheduled tasks [closed]运行计划任务的最佳方式[关闭]
【发布时间】:2010-10-07 06:25:08
【问题描述】:

今天我们构建了一个控制台应用程序,用于为我们的 ASP.NET 网站运行计划任务。但我认为这种方法有点容易出错并且难以维护。你如何执行你的计划任务(在 windows/IIS/ASP.NET 环境中)

更新:

任务示例:

  • 从数据库中的电子邮件队列发送电子邮件
  • 从数据库中删除过时的对象
  • 从 Google AdWords 检索统计信息并在数据库中填写表格。

【问题讨论】:

标签: asp.net windows iis scheduled-tasks


【解决方案1】:

创建一个custom Windows Service

我将一些关键任务任务设置为计划的控制台应用程序,但发现它们难以维护。我创建了一个带有“心跳”的 Windows 服务,它会每隔几分钟检查一次我的数据库中的时间表。效果非常好。

话虽如此,我仍然使用计划的控制台应用程序来完成大多数非关键维护任务。如果它没有坏,就不要修理它。

【讨论】:

  • 仅供参考,链接现已失效。
  • @CharlesBurns,您可以随时使用 archive.org 浏览死链接:web.archive.org/web/20090919131944/http://www.dotheweb.net/…
  • 控制台应用程序和windows服务解决的难点是什么?我们对所有任务使用控制台脚本,但调度程序是数据库引擎作业代理。我们正在考虑围绕它构建一些 Web GUI,并在应用程序级别管理访问权限(调度程序将成为其自己的 Web 应用程序的一部分)。
【解决方案2】:

This technique by Jeff Atwood for Stackoverflow 是我遇到的最简单的方法。它依赖于 ASP.NET 缓存系统中内置的“缓存项已删除”回调机制

更新:Stackoverflow 已经超越了这种方法。它仅在网站运行时有效,但它是一种非常简单的技术,对许多人都很有用。

还可以查看Quartz.NET

【讨论】:

  • 那么如果应用程序没有运行,但计划任务需要发生,会发生什么?
  • 如果这次任务恰好需要一段时间才能运行,这也可能会降低用户体验。我不想让用户为我生成维护/任务。
  • 这太可怕了!任何事情都可能导致应用程序停止运行,并且可能只会在下一个用户请求时重新启动。在这些时间之间,您的任务不会运行!
  • 我今天在原始博客文章的 cmets 中注意到的一点:No, we’ve switched to a dedicated task. We definitely outgrew this technique. I do think it’s fine for small sites though! -- Jeff Atwood
  • -1 这种方法有一个很大的缺陷。每当应用程序被回收时,“CacheItemRemoved”事件就会触发并且您的计划任务将运行。在生产现场,这可能每天发生几次。如果您希望任务每周运行,那就不太好。
【解决方案3】:

为什么要重新发明轮子,使用 Threading 和 Timer 类。

    protected void Application_Start()
    {
        Thread thread = new Thread(new ThreadStart(ThreadFunc));
        thread.IsBackground = true;
        thread.Name = "ThreadFunc";
        thread.Start();
    }

    protected void ThreadFunc()
    {
        System.Timers.Timer t = new System.Timers.Timer();
        t.Elapsed += new System.Timers.ElapsedEventHandler(TimerWorker);
        t.Interval = 10000;
        t.Enabled = true;
        t.AutoReset = true;
        t.Start();
    }

    protected void TimerWorker(object sender, System.Timers.ElapsedEventArgs e)
    {
        //work args
    }

【讨论】:

  • 你不需要产生线程来启动计时器...
  • 我也不认为这是一个理想的解决方案。
  • @IdanShechter 最好说明一下您认为这不是理想解决方案的原因
  • 线程可能有问题,因为不是HttpRequest,一些涉及HttpRequest的数据可以为null。例如 HttpRequest .ApplicationPath。如果任务编写得当,它将起作用。另一个问题是应用程序池重新启动。如果池重启太频繁(内存泄漏...),worker 将永远不会运行。
  • 如果您有多个实例正在运行(例如负载平衡) - 可能您不想要这个解决方案(几个任务做同样的事情)
【解决方案4】:

使用 Windows Scheduler 运行网页。

为防止恶意用户或搜索引擎蜘蛛运行它,当您设置计划任务时,只需使用查询字符串调用网页,即:mypage.aspx?from=scheduledtask

然后在页面加载中,只需使用一个条件: if (Request.Querystring["from"] == "scheduledtask") { //执行任务 }

这样,搜索引擎蜘蛛或恶意用户将无法执行您的计划任务。

【讨论】:

  • 更好的是,使用加盐散列算法来验证查询字符串,比魔术短语更安全。 req 类似于 mypage.aspx?salt=foo&hash=1223523jbhdgu13t1。您只需要在服务器和客户端上使用相同的散列算法即可。还要在服务器上添加硬限制;执行时保存,防止执行过快。不过我可能有点偏执。
  • 更安全的是,使用 Windows Scheduler 运行一个网页来检查请求是否来自服务器本身:Request.IsLocal >> 只有服务器本身可以运行计划任务,没有其他人可以运行.
  • 您的方法是否有更多经验?我打算为我们的应用程序开发类似类型的服务,现在我无法决定是否更好地调用具有计划任务或 cron 的页面,或者是否使用缓存系统。
【解决方案5】:

我为一个网站执行的所有任务(需要安排)都保存在该网站内,并从一个特殊页面调用。然后我编写了一个简单的 Windows 服务,它每隔一段时间就会调用这个页面。一旦页面运行,它就会返回一个值。如果我知道还有更多工作要做,我会立即再次运行该页面,否则我将在稍后运行它。这对我来说非常有效,并将我的所有任务逻辑都保留在 Web 代码中。在编写简单的 Windows 服务之前,我使用 Windows 调度程序每 x 分钟调用一次页面。

另一个方便的运行方式是使用Pingdom 之类的监控服务。将他们的 http 检查指向运行您的服务代码的页面。让页面返回结果,然后可用于触发 Pingdom 在出现问题时发送警报消息。

【讨论】:

  • 这是我最终得到的解决方案。我使用 windows scheduler + curl 而不是自定义 Web 服务。使用 Windows 服务有什么好处。
  • 你看过缓存项过期技术吗?我想你会发现它是一个更理想的定时服务实现:codeproject.com/KB/aspnet/ASPNETService.aspx
  • 如何阻止恶意用户(或搜索引擎蜘蛛)调用此页面,从而导致您的计划任务运行?
  • 您可以通过在 Web 应用中存储静态时间戳来阻止恶意调用,并且仅在未设置时间戳(第一次调用)或自上次调用后正确时间已过期时才运行。
  • 我通过检查 ip 地址是否是内部地址来阻止对我的 url 的恶意调用。如果它不是我们组织内部的,它什么也不返回,也不做任何事情。
【解决方案6】:

您可以使用“ThreadPool.RegisterWaitForSingleObject”方法轻松创建间隔运行代码的 Windows 服务。它真的很流畅,很容易设置。与使用框架中的任何计时器相比,此方法是一种更精简的方法。

查看以下链接了解更多信息:

使用 Windows 服务在 .NET 中运行定期进程:
http://allen-conway-dotnet.blogspot.com/2009/12/running-periodic-process-in-net-using.html

【讨论】:

    【解决方案7】:

    .NET 的新任务计划程序类库

    注意:自创建此库以来,Microsoft 为 Windows Vista 引入了新的任务计划程序(Task Scheduler 2.0)。该库是 Task Scheduler 1.0 接口的包装器,该接口在 Vista 中仍然可用,并且与 Windows XP、Windows Server 2003 和 Windows 2000 兼容。

    http://www.codeproject.com/KB/cs/tsnewlib.aspx

    【讨论】:

    • 请删除。下面已经回答了。重复
    【解决方案8】:

    这个图书馆就像一个魅力 http://www.codeproject.com/KB/cs/tsnewlib.aspx

    它允许您直接通过您的 .NET 代码管理 Windows 计划任务。

    【讨论】:

      【解决方案9】:

      我发现这对所有参与者来说都很容易:

      • 创建 Web 服务方法,例如 DoSuchAndSuchProcess
      • 创建一个调用此网络方法的控制台应用程序。
      • 在任务计划程序中计划控制台应用程序。

      使用此方法,所有业务逻辑都包含在您的 Web 应用程序中,但您可以使用 Windows 任务管理器或任何其他商业任务管理器来启动它并记录任何返回信息,例如执行报告。使用 Web 服务而不是发布到页面有一点优势,因为它更容易从 Web 服务获取返回数据。

      【讨论】:

        【解决方案10】:

        这是另一种方式:

        1) 创建一个“心跳”网络脚本,负责在任务到期或逾期启动时启动任务。

        2) 在某处(最好在同一 Web 服务器上)创建一个计划进程,该进程会命中 webscript 并强制它定期运行。 (例如,使用 IE 或 whathaveyou 悄悄启动 heatbeat 脚本的 windows 调度任务)

        任务代码包含在 Web 脚本中的事实纯粹是为了将代码保留在 Web 应用程序代码库中(假设两者相互依赖) ,这对 Web 开发人员来说更容易管理。

        另一种方法是创建一个可执行的服务器脚本/程序,它自己完成所有计划工作,并将可执行文件本身作为计划任务运行。这可以允许 Web 应用程序和计划任务之间的基本解耦。因此,如果即使 Web 应用程序/数据库可能已关闭或无法访问,您也需要运行计划任务,您应该采用这种方法。

        【讨论】:

        • @Matias,为什么不让预定的流程来做真正的工作呢?
        【解决方案11】:

        此外,如果您的应用程序使用 SQL SERVER,您可以使用 SQL 代理来安排您的任务。这是我们通常放置重复出现的数据驱动代码(电子邮件提醒、计划维护、清除等)的地方。 SQL 代理内置的一个很棒的功能是失败通知选项,它可以在关键任务失败时提醒您。

        【讨论】:

          【解决方案12】:

          我在一个 ASP.NET 项目中成功使用了Abidar(这里有一些background information)。

          此方法的唯一问题是,如果 ASP.NET Web 应用程序从内存中卸载(即由于使用率低),任务将无法运行。我尝试过的一件事是创建一个任务,每 5 分钟访问一次 Web 应用程序,使其保持活动状态,但这似乎不能可靠地工作,所以现在我使用 Windows 调度程序和基本控制台应用程序来代替。

          理想的解决方案是创建 Windows 服务,尽管这可能是不可能的(即,如果您使用的是共享主机环境)。从维护的角度来看,它还可以让事情更容易地保留在 Web 应用程序中。

          【讨论】:

            【解决方案13】:

            一种选择是设置 Windows 服务并让它调用您的计划任务。

            在我使用过 Timers put 的 winforms 中,我认为这在 ASP.NET 中效果不佳

            【讨论】:

              【解决方案14】:

              如果您拥有服务器,则应使用 Windows 任务调度程序。使用 AT/?从命令行查看选项。

              否则,在基于 Web 的环境中,您可能不得不做一些令人讨厌的事情,例如设置另一台机器以按时间间隔向某个页面发出请求。

              【讨论】:

                【解决方案15】:

                我们也使用控制台应用程序。如果您使用 Log4net 等日志工具,您可以正确监控它们的执行。另外,我不确定它们比网页更难维护,因为如果设计得当,您可能会在两者之间共享一些相同的代码库。

                如果您反对定时运行这些任务,您可以在网站的管理部分中设置一个网页作为队列。用户提出运行任务的请求,然后它会在 MyProcessQueue 表中插入空白日期戳记录,并且您的计划任务每​​ X 分钟检查一次 MyProcessQueue 中的新记录。这样,它只会在客户希望它运行时运行。

                希望这些建议有所帮助。

                【讨论】:

                  【解决方案16】:

                  我不确定您指的是哪种计划任务。如果您的意思是“每小时刷新 foo.xml”类型的任务,请使用 Windows 计划任务系统。 (“at”命令,或通过控制器。)让它运行控制台应用程序或请求启动进程的特殊页面。

                  编辑:我应该补充一点,这也是让您的 IIS 应用程序在预定点运行的好方法。因此,假设您想每 30 分钟检查一次数据库,并通过电子邮件向用户发送有关某些数据的提醒,您可以使用计划任务来请求此页面,从而让 IIS 处理事情。

                  如果您的需求更复杂,您可以考虑创建一个 Windows 服务并让它运行一个循环来执行您需要的任何处理。这还具有分离代码以用于扩展或管理目的的好处。不利的一面是,您需要处理 Windows 服务。

                  【讨论】:

                    猜你喜欢
                    • 2019-11-22
                    • 1970-01-01
                    • 1970-01-01
                    • 2010-09-08
                    • 1970-01-01
                    • 2023-03-08
                    相关资源
                    最近更新 更多