开源的.NET定时任务组件Hangfire解析

   项目中很多时候都会使用到定时任务这样一个功能需求,在.NET中对于完成定时任务的技术还是不怎么多的,.NET Framework具有“内置”定时器功能,通过System.Timers.Timer类。在使用Timer类需要面对的问题:计时器没有持久化机制;计时器具有不灵活的计划(仅能设置开始时间和重复间隔,没有基于日期,时间等);计时器不使用线程池(每个定时器一个线程);计时器没有真正的管理方案 - 你必须编写自己的机制,以便能够记住,组织和检索任务的名称等。如果需要在.NET实现定时器的功能,可以尝试使用以下这款开源免费的组件Quartz.Net组件。

  上面介绍了两种方式,在这里就介绍另外一种组件,那就是Hangfire组件。

一.Hangfire组件概述

在.NET和.NET Core应用程序中执行后台处理的简单方法。无需Windows服务或单独的进程。由持久存储支持,存储方式有sqlserver、redis,mongodb等等。Hangfire支持所有类型的后台任务 - 短时间运行和长时间运行,CPU密集型和I / O密集型,一次性和周期性。

   1.组件特点:

   2.组件功能:

      上面是对Hangfire组件背景的一些简单介绍,下面我们具体来了解一下Hangfire组件的使用方法。

二.Hangfire组件使用方法介绍

      既然想要学习了解一个组件,当然需要知道是怎么样取使用,如果不能使用,学着也没有什么很大的用处,下面介绍一下Hangfire组件的一些常用方法。

1.ASP.NET MVC设置方式:

public void Configuration(IAppBuilder app)
{
    GlobalConfiguration.Configuration.UseSqlServerStorage("<connection string or its name>");
    app.UseHangfireDashboard();
    app.UseHangfireServer();
}

GlobalConfiguration类是配置Hangfire的首选方式。这是一些方法的入口点,包括来自第三方存储实现或其他扩展的方法。用法很简单,只需Hangfire在应用程序初始化类中包含命名空间,并发现GlobalConfiguration.Configuration属性的扩展方法

   2.控制台设置方式:

 GlobalConfiguration.Configuration
                .UseColouredConsoleLogProvider()                         .UseSqlServerStorage(@"Server=.\sqlexpress;Database=Hangfire.Sample;Trusted_Connection=True;")
                .UseMsmqQueues(@".\Private$\hangfire{0}", "default", "critical");

3.基于队列的任务处理:

var jobId = BackgroundJob.Enqueue(
    () => Console.WriteLine("Fire-and-forget!"));

4.延迟任务执行:

var jobId = BackgroundJob.Schedule(
    () => Console.WriteLine("Delayed!"),
    TimeSpan.FromDays(7));

5.循环任务执行:

RecurringJob.AddOrUpdate(
    () => Console.WriteLine("Recurring!"),
    Cron.Daily);

6.继续在其父作业完成时执行:

BackgroundJob.ContinueWith(
    jobId,
    () => Console.WriteLine("Continuation!"));

7.批处理方法:

var batchId = BatchJob.StartNew(x =>
{
    x.Enqueue(() => Console.WriteLine("Job 1"));
    x.Enqueue(() => Console.WriteLine("Job 2"));
});

8.当父批次中的所有后台作业完成时,批处理继续:

BatchJob.ContinueWith(batchId, x =>
{
    x.Enqueue(() => Console.WriteLine("Last Job"));
});

   9.使用IoC容器:

public  class  ContainerJobActivator  : JobActivator 
{ 
    private  IContainer  _container ;
    public  ContainerJobActivator (IContainer  container )
    { 
        _container  =  container ; 
    }}
    public  override  object  ActivateJob (Type  type )
    { 
        return  _container 。Resolve (type ); 
    } 
}

    在启动Hangfire服务器之前将其注册为当前作业启动器。

var container = new Container();
GlobalConfiguration.Configuration.UseActivator(new ContainerJobActivator(container));
...
app.UseHangfireServer();

      Hangfire将作业保存到持久存储中,并以可靠的方式处理它们。这意味着你可以中止Hangfire工作线程,卸载应用程序域甚至终止进程,工作将被处理。Hangfire将作业标记为已完成,只有当代码的最后一行执行,并知道作业可能会失败,最后一行。它包含不同的自动重试功能,可以处理代码中的存储错误或错误。

三.Hangfire组件核心对象解析

   上面介绍了Hangfire组件的常用方法,Hangfire组件的功能非常多,这里就做介绍了,有兴趣可以去官网进行查看api。下面介绍一下Hangfire组件的一些核心对象,初探Hangfire组件深层次的问题。

 1.RecurringJob.AddOrUpdate():

 public static void AddOrUpdate(
            Expression<Action> methodCall,
            string cronExpression,
            TimeZoneInfo timeZone = null,
            string queue = EnqueuedState.DefaultQueue)
        {
            var job = Job.FromExpression(methodCall);
            var id = GetRecurringJobId(job);

            Instance.Value.AddOrUpdate(id, job, cronExpression, timeZone ?? TimeZoneInfo.Utc, queue);
        }

   该方法用于定期作业在指定的CRON计划上触发多次。该方法具有16个重载,Job.FromExpression(methodCall);用于获取基于Job类的新实例给定的方法调用的表达式树。GetRecurringJobId(job)方法根据Job对象获取对应的JobID。

2.BackgroundJob.Enqueue():

public static string Enqueue([NotNull, InstantHandle] Expression<Action> methodCall)
        {
            var client = ClientFactory();
            return client.Enqueue(methodCall);
        }

   该方法基于给定的方法调用表达式创建一个新的fire-and-forget作业。该方法接受一个参数,表示将被编组到服务器的方法调用表达式。接下来我们看一下var client = ClientFactory();方法的具体实现

internal static Func<IBackgroundJobClient> ClientFactory
        {
            get
            {
                lock (ClientFactoryLock)
                {
                    return _clientFactory ?? DefaultFactory;
                }
            }
            set
            {
                lock (ClientFactoryLock)
                {
                    _clientFactory = value;
                }
            }
        }

   该属性定义了一个Func<IBackgroundJobClient>的泛型委托。该属性是一个可读可写的操作,对ClientFactoryLock加锁,确保不发生死锁情况。

四.总结

    上面简单的介绍了Hangfire组件的背景和一些简单的应用,也着重的介绍了一些对象。这个组件的功能很强大,需要了解的地方也较多,这一篇文章不可能全部介绍,用做抛砖引玉的作用。在这里吐槽一句,微软最近技术发展太快,很多技术还没有来得及发展,就有新的技术出来,让我们这些底层的人着实难受,事物发展有规律,不是以前缺的东西可以在很短的时间就可以补上,还是需要留下足够的空间。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏你不就像风一样

网络爬虫之Url含有中文如何转码

902
来自专栏纯洁的微笑

springboot(十一):Spring boot中mongodb的使用

mongodb是最早热门非关系数据库的之一,使用也比较普遍,一般会用做离线数据分析来使用,放到内网的居多。由于很多公司使用了云服务,服务器默认都开放了外网地址,...

3046
来自专栏圣杰的专栏

ABP入门系列(10)——扩展AbpSession

源码路径:Github-LearningMpaAbp 一、AbpSession是Session吗? 1、首先来看看它们分别对应的类型是什么? 查看源码发现Ses...

2926
来自专栏WindCoder

微信小程序踩坑记-Java基于SSM下的post请求

最近在持续踩微信小程序的坑,canvas和WebSocket的暂时还没找到相关的解决方案,暂时先将post请求无法获取data参数的坑填上。直接附上解决方案,已...

2751
来自专栏梦里茶室

sqlite在Android上的一个bug:SQLiteCantOpenDatabaseException when nativeExecuteForCursorWindow

这是sqlite在Android系统上的一个bug,在需要建立索引的sql语句频繁执行时,会发生这个异常。

922
来自专栏c#开发者

C#开发终端式短信的原理和方法

简介   没发过短信的年轻人肯定是属于那种受保护的稀有动物,通讯发达的今天短信已经成为人们交流的重要手段,其中也蕴含着巨大的市场和经济利益,掌握短信技术的人才也...

3509
来自专栏马洪彪

Java生成条码二维码

一、概述 可用barcode4j或zxing等第三方库,推荐zxing。 barcode4j资料链接:http://barcode4j.sourceforge....

4448
来自专栏草根专栏

使用xUnit为.net core程序进行单元测试(4)

数据驱动的测试 打开PlayerCharacterShould.cs 添加几个Fact测试方法: [Fact] public v...

2844
来自专栏梦里茶室

sqlite在Android上的一个bug:SQLiteCantOpenDatabaseException when nativeExecuteForCursorWindow

12-14 19:51:30.346 17770-18098/com.company.product W/System.err: com.company.pr...

4129
来自专栏草根专栏

使用xUnit为.net core程序进行单元测试(下2)

第1部分: https://cloud.tencent.com/developer/article/1019835

2367

扫码关注云+社区