IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    如何在ASP.NET应用中执行定时任务

    汪宇杰发表于 2014-07-18 02:28:05
    love 0

    在ASP.NET里运行定时任务,这是个老生常谈的话题了,撇开那些用per request搞定屌丝办法,目前最好的解决办法只有2种:

    1. ���果你有大微软的Azure,可以直接在网站服务中找到Jobs,自己看一下就会了

    2. 如果你是屌丝,买不起Azure,就用本文介绍的WebBackgrounder搞

    由于ASP.NET是服务器端Web框架,所以一般而言,一个操作的往往是只有收到客户端Request之后才能执行的,如果网站一直没人访问,没有Request进来,如何执行代码呢?定时任务就是这种坑爹场景。

    还好,大微软的MVC帝、ASP.NET小王子haacked蜀黍给我们写了个 http://www.nuget.org/packages/WebBackgrounder/ 专门捣鼓这种场景。作为一个屌丝程序猿,和大牛的区别就在于“好编程,不求甚解”。所以我们不必在意它是怎么实现的,只要会用就行了。我在公司的项目中就用了一下,感觉很爽。

    1. 首先,你要用高大上的ASP.NET 4.5(用低版本的都去吃翔吧

    为了装逼,我们要通过命令行安装WebBackgrounder的NuGet包:

    PM> Install-Package WebBackgrounder 

    2. 新建一个静态类,名字任意,我取名为“WebBackgrounderSetup.cs”(名字也是可以反映逼格的,最好以Setup结尾

    3. 在namespace外面,注意,一定一定要在namespace的外面!!!!!!加上这两行代码,用来注册在ASP.NET应用启动和结束时要触发的方法。

    [assembly: WebActivatorEx.PostApplicationStartMethod(typeof(你的命名空间.WebBackgrounderSetup), "Start")]
    [assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(你的命名空间.WebBackgrounderSetup), "Shutdown")]

    4. 根据你的需求,创建一个类,继承Job,比如我这个:

    /// 
    /// Job To Refresh Project Tree into Memory
    /// 
    public class GetCucumberProjectTreeJob : Job
    {
        public GetCucumberProjectTreeJob(TimeSpan interval, TimeSpan timeout)
            : base("GetCucumberProjectTree Job", interval, timeout)
        {
        }
    
        public override Task Execute()
        {
            return new Task(() =>
            {
                Logger.Debug("Refreshing Project Tree...");
                Utils.Projects = Utils.GetTreeFromDisk();
            });
        }
    }

    注意构造函数,是继承Job父类的,"GetCucumberProjectTree Job"是你的Job的名字,interval是每次执行间隔时间,timeout是单次操作的超时时间,如果超时,这次Job就会被撸掉。Execute方法里面的就是你要执行的代码,因为方法返回类型是个Task,所以要把你的代码包在Task里面。

    5. 把你创建的这个Job塞到刚才的WebBackgrounderSetup里面。代码看起来就像是这样:

    public static class WebBackgrounderSetup
    {
        static readonly JobManager _jobManager = CreateJobWorkersManager();
    
        public static void Start()
        {
            _jobManager.Start();
        }
    
        public static void Shutdown()
        {
            _jobManager.Dispose();
        }
    
        private static JobManager CreateJobWorkersManager()
        {
            var jobs = new IJob[]
            {
                new GetCucumberProjectTreeJob(TimeSpan.FromSeconds(5 * 60), TimeSpan.FromSeconds(20)),
            };
    
            var coordinator = new SingleServerJobCoordinator();
            var manager = new JobManager(jobs, coordinator);
            manager.Fail(ex => Logger.Error("Web Job Blow Up.", ex));
            return manager;
        }
    }

    因为这里我只有一个Job要执行,所以IJobs[]数组里面只赛了一个对象。如果��有很多Job要调度,都可以往这个数字里塞。

    我需要每5分钟执行一次Job,每次超时20秒,就这样写:

    new GetCucumberProjectTreeJob(TimeSpan.FromSeconds(5 * 60), TimeSpan.FromSeconds(20))

    其中写5 * 60是个很流行的代码装逼方法,可以增加可读性,并且编译器在编译时候其实是把计算后的结果编译进去的,所以不会每次执行都去计算,即保住了逼格,也不影响性能。

    处理Job执行中的异常,用的是

    manager.Fail

    里面塞的是一个委托,take的是爆破的Exception对象,在这里我只是记录一下Log,你可以自由发挥。

    6. 有图有真相:



沪ICP备19023445号-2号
友情链接