运行计划任务的最佳方法


229

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

更新:

任务示例:

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

您正在运行的任务的一个例子是什么?
JeffO

4
您需要检查atrigger.com
Kousha的

如果您有Plesk,则可以编写vbs并将其添加到任务计划程序中:net24.co.nz/kb/article/AA-00213/13/Shared-Hosting/ASP-ASP.NET/…– HasanG 2014
6

Answers:


74

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

另一方便的运行方法是使用Pingdom之类的监视服务。将他们的http检查指向运行您的服务代码的页面。具有页面返回结果,然后可以将其用于在某些不正确的情况下触发Pingdom发送警报消息。


3
这就是我最终得到的解决方案。代替自定义Web服务,我使用Windows Scheduler + curl。使用Windows服务有什么好处。
Niels Bosma,2009年

16
您是否看过“缓存项过期”技术?我认为您会发现它是计划服务的更理想的实现:codeproject.com/KB/aspnet/ASPNETService.aspx
Richard Clayton,2009年

10
如何阻止恶意用户(或搜索引擎蜘蛛)调用此页面,从而导致计划的任务运行?
09年

8
您可以通过在Web应用程序中存储静态时间戳来停止恶意呼叫,并仅在未设置时间戳(首次呼叫)或自上次呼叫以来的正确时间到期后才运行,以阻止恶意呼叫。
罗伯·肯特

5
我通过检查IP地址是否是内部地址来阻止对URL的恶意调用。如果它不是我们组织内部的,它什么也不返回,什么也不做。
user1408767'7

128

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

更新:Stackoverflow已不再支持此方法。它仅在网站运行时有效,但这是一种非常简单的技术,对许多人有用。

还要检查Quartz.NET


12
那么,如果应用程序未运行但计划任务需要执行,会发生什么呢?
-MichaelGG,

2
如果任务恰好需要一段时间才能运行,这也可能减慢用户体验。我不希望用户为我生成维护/任务。
Brettski,

5
这太可怕了!任何情况都可能导致应用程序停止运行,并且可能仅在下一个用户请求时重新启动。在这段时间之间,您的任务不会运行!
teedyay,2009年

43
我今天在原始博客文章的评论中注意到了一些东西: No, we’ve switched to a dedicated task. We definitely outgrew this technique. I do think it’s fine for small sites though!-杰夫·阿特伍德
乔尔

3
-1这种方法有一个很大的缺陷。每当回收应用程序时,都会触发“ CacheItemRemoved”事件,并且您的计划任务将运行。在生产站点上,一天可能会发生几次。如果您希望任务每周运行,那就不太好。
Steven de Salas 2014年

30

创建一个自定义Windows服务

我将一些关键任务设置为计划的控制台应用程序,发现它们难以维护。我创建了一个带有“心跳”功能的Windows服务,该服务每两分钟检查一次数据库中的计划。真的很好。

话虽如此,我仍然将调度的控制台应用程序用于大多数非关键维护任务。如果没有损坏,请不要修复。


7
仅供参考,链接现在已消失。
查尔斯·伯恩斯

1
@CharlesBurns,您始终可以使用archive.org浏览无效链接:web.archive.org/web/20090919131944/http
Nikolay Kostov,

17

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

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

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


10

为什么要重新发明轮子,请使用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
    }

7
您无需生成线程即可启动计时器...
Zyo 2012年

4
我也不认为这是理想的解决方案。
伊丹·谢希特

12
@IdanShechter,最好告诉您您认为这不是理想解决方案的原因
Omu 2012年

2
线程可能会出现问题,因为它不是HttpRequest,涉及HttpRequest的某些数据可能为null。例如HttpRequest .ApplicationPath。如果任务编写正确,它将起作用。另一个问题是应用程序池重新启动。如果池重新启动的频率太高(内存泄漏...),则工作线程将永远无法运行。
Tomas Kubes 2013年

2
如果您有多个实例在运行(例如,负载平衡)-可能您不想要此解决方案(几个任务都在做同样的事情)
Illidan 2014年

8

使用Windows Scheduler运行网页。

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

然后在页面加载中,只需使用以下条件:if(Request.Querystring [“ from”] ==“ scheduledtask”){// executetask}

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


5
更好的是,使用一种盐化的哈希算法,该算法实际上比魔术短语更安全地验证了查询字符串。该请求将类似于mypage.aspx?salt = foo&hash = 1223523jbhdgu13t1。您只需要在服务器和客户端上使用相同的哈希算法即可。同时在服务器上增加硬限制;保存执行时间,并防止执行得太快。我可能会偏执。
Nenotlep

14
更安全的是,使用Windows Scheduler运行一个网页,以检查请求是否来自服务器本身:Request.IsLocal>>仅服务器本身可以运行计划的任务,其他人不能运行。
阴谋

您的方法是否有更多经验?我打算开发与我们的应用程序类似的服务,但现在我无法确定是否最好使用计划任务或cron来调用页面,还是使用缓存系统。
JayDee


3

此外,如果您的应用程序使用SQL SERVER,则可以使用SQL代理来计划任务。这是我们通常放置由数据驱动的重复发生代码的地方(电子邮件提醒,计划的维护,清除等)。SQL Agent内置的一项重要功能是故障通知选项,如果关键任务失败,该选项可以提醒您。


2

我不确定您要执行的预定任务是什么。如果您指的是诸如“每小时刷新foo.xml”之类的任务,请使用Windows Scheduled Tasks系统。(“ at”命令,或通过控制器。)让它运行控制台应用程序或请求启动该过程的特殊页面。

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

如果您的需求更为复杂,则可以考虑创建Windows服务,并使其运行循环以执行所需的任何处理。这也具有将代码分离出来以进行缩放或管理的好处。不利的一面是,您需要处理Windows服务。


2

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

否则,在基于Web的环境中,您可能必须做一些讨厌的事情,例如设置另一台计算机,以在一定时间间隔内向特定页面发出请求。


2

我已经在ASP.NET项目中成功使用了Abidar(这是一些背景信息)。

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

理想的解决方案是创建Windows服务,尽管这可能是不可能的(即,如果您使用共享主机环境)。从维护的角度来看,这也使得将内容保留在Web应用程序中变得容易一些。


1

这是另一种方式:

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

2)在某个地方(最好是在同一台Web服务器上)创建一个计划进程,该进程会命中该Web脚本并强制其定期运行。(例如,Windows计划任务使用IE或whathaveyou静默启动heatbeat脚本)

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

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


1
@Matias,为什么不只是按计划进行实际工作呢?
路加福音


0

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

如果您反对让这些任务按时运行,则可以在网站的管理部分中将一个网页作为队列。用户发出运行任务的请求,它依次在MyProcessQueue表上插入空白的datetamp记录,并且您计划的任务每隔X分钟检查一次MyProcessQueue中的新记录。这样,它仅在客户希望运行时运行。

希望这些建议对您有所帮助。


0

一种选择是设置Windows服务,并使其调用计划的任务。

在Winforms中,我使用了Timers put,认为这在ASP.NET中不能很好地工作


-1

NET的新任务计划程序类库

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

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


请删除。已在下面回答。重复
Fandango68年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.