Timed Job - Pomelo扩展包系列

Published on 6/12/2016 9:03:04 PM

Introduction

许多.NET开发者向我反馈,在不使用Azure Jobs的时候,做定时事件太麻烦。因此设计了Timed Job框架以供开发者在进行ASP.NET Core时,能够拥有低后期维护成本、条理清晰地编写定时事务逻辑。具体可以应用于定时生成报表、定时生成网站缓存等场景。

Getting Started

使用方法很简单,首先引用Pomelo.AspNetCore.TimedJob包(注意,该包没有包含在Pomelo.AspNetCore.Extensions中)。当然这要添加MyGet Feed:<add key="Code Comb" value="https://www.myget.org/F/pomelo/api/v2/" />

在Startup.cs中添加TimedJob:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

namespace TimedJobSite
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTimedJob();
        }

        public void Configure(IApplicationBuilder app)
        {
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("Hello World!");
            });

            app.UseTimedJob();
        }
    }
}

然后在你的ASP.NET Core项目下创建一个Jobs文件夹,其实不创建也可以。接下来创建一个类叫XXXJob.cs,继承Pomelo.AspNetCore.TimedJob.Job

file

接下来,你可以为你的Job类添加构造函数,构造函数的参数中可以是任何DependencyInjection中的service,比如你可以填写DbContext或是IHostingEnvironment等等。同样,在Job类中的所有方法的参数也可以是DependencyInjection中的任何service。最后为Job类中的方法,添加上[Invoke]特性即可完成自动触发:

using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Pomelo.AspNetCore.TimedJob;

namespace TimeJobSite.Jobs
{
    public class GarbageCollectJob : Job
    {
        [Invoke(Begin = "2016-6-12 18:00", Interval = 1000 * 60)]
        public void Collect(IServiceProvider services)
        {
            var env = services.GetRequiredService<IHostingEnvironment>();
            Console.WriteLine($"{ env.ContentRootPath } Collecting...");
            GC.Collect();
        }
    }
}

Dynamic Invoking

Pomelo为开发者设计了通过DB来控制Invoke的逻辑。这样一来,开发者编写的就不是Hard Code了,可以通过修改数据库中内容,来修改Job的调用方式,如周期、起始时间等。

首先,将DbContext实现ITimedJobContext接口:

using Microsoft.EntityFrameworkCore;
using Pomelo.AspNetCore.TimedJob.EntityFramework;

namespace TimedJobSite.Models
{
    public class TimedJobSiteContext : DbContext, ITimedJobContext
    {
        public TimedJobSiteContext(DbContextOptions opt) 
            : base(opt)
        {
        }

        public DbSet<TimedJob> TimedJobs { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.SetupTimedJobs();
        }
    }
}

在Startup.cs中添加TimedJob的扩展组件,并填写实现了ITimedJobContext接口的DbContext类型参数:

            services.AddTimedJob()
                .AddEntityFrameworkDynamicTimedJob<TimedJobSiteContext>();

在Jobs文件夹中新建一个PrintJob.cs类并继承Job类:

using System;
using Pomelo.AspNetCore.TimedJob;

namespace TimedJobSite.Jobs
{
    public class PrintJob : Job
    {
        public void Print()
        {
            Console.WriteLine("Test dynamic invoke...");
        }
    }
}

编写数据库初始化类SampleData.cs:

using System;
using Microsoft.Extensions.DependencyInjection;
using Pomelo.AspNetCore.TimedJob;

namespace TimedJobSite.Models
{
    public static class SampleData
    {
        public static void InitDB(IServiceProvider services)
        {
            var DB = services.GetRequiredService<TimedJobSiteContext>();
            var TimedJobService = services.GetRequiredService<TimedJobService>();
            DB.Database.EnsureCreated();
            DB.TimedJobs.Add(new Pomelo.AspNetCore.TimedJob.EntityFramework.TimedJob
            {
                Id = "TimedJobSite.Jobs.PrintJob.Print", // 按照完整类名+方法形式填写
                Begin = DateTime.Now,
                Interval = 3000,
                IsEnabled = true
            }); // 添加一个定时事务
            DB.SaveChanges();
            TimedJobService.RestartDynamicTimers(); // 增删改过数据库事务后需要重启动态定时器
        }
    }
}

在Startup.cs中调用数据库初始化方法:

        public void Configure(IApplicationBuilder app)
        {
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("Hello World!");
            });

            app.UseTimedJob(); // 使用定时事务
            SampleData.InitDB(app.ApplicationServices); // 初始化数据库
        }

至此即实现了动态设定调用参数的逻辑。本示例源代码:点击下载源代码

Share to:

Comments

使用微信扫码