D-08-排程设定 ? hangfire

如何处理定期的需求

相信很多人会遇到需要定期做某些事情的状况,例如每分钟去计算一次资料,或者一分钟跟资料库捞取资料的需求,这时如果写Windows Service或是Console程序再搭配Windows排程来设定是一个解决方法,但是没办法看到排程的相关资讯,而且还要记得去作业系统设定服务或是排程之类的,不过今天可以有另外一个选择,请大家继续看下去。

本文同步放置於此

hangfire

「前辈,今天需要做一个每分钟爬取汇率的功能耶,我没有做过这类的」
今天大头要来做一个一分钟爬取汇率的功能,但是因为没有做过所以很苦恼,这时看到老K走进来所以急急忙忙地询问一下。
「恩~~~你就做一个while然後Task.Delay(60000)不就好了。」
老K听到大头的问题後就这样回答他,不过大头听了之後的表情不是很满意,这时候老K笑笑地对他说。
「哈哈哈,开玩笑的啦你可以写一个写一个Console程序,然後看是挂CronJob还是Windows排程就好了。」
大头听了这个回答之後,虽然不是很满意但是看起来准备要去开始动工了,这时老K叫住了他。
「好了好了不闹你了,刚刚都是开玩笑的,你可以去研究一下hangfire。」
这时候小光刚好走了过来,老K看到他後跟大头这麽说。
「你就跟他一起去研究一下吧。」

环境设定

在开始开发排程程序之前先设定一下环境。所以先输入以下指令来加载套件。

dotnet add package Hangfire.AspNetCore
dotnet add package Hangfire.Autofac
dotnet add package Hangfire.MemoryStorage

这里说明一下,因为hangfire会把排程以及要输入的参数存放起来,不过这边我们可以选择把资料放在记忆体中,如此可以避免大量存取资料库的问题,不过要小心记忆体增长的问题,所以要去清理已经完成的资料。在加载套件完成之後我们来注册排程到我们的程序里面,首先先在Statrup.Configure加入以下内容。

GlobalConfiguration.Configuration
    .UseActivator(new HangfireActivator(provider));

app.UseHangfireServer(new BackgroundJobServerOptions
{
    SchedulePollingInterval = TimeSpan.FromMilliseconds(1000)
});
app.UseHangfireDashboard("/hangfire",
    new DashboardOptions()
    {
        Authorization = new[] { new AllowAllConnectionsFilter() },
        IgnoreAntiforgeryToken = true
    });

其中SchedulePollingInterval是设定多久检查排程一次,预设是15秒,这部分相关内容可以参考使用 Hangfire OWIN 建立非同步任务,再来UseHangfireDashboard是建立内建的hangfire的操作画面,GlobalConfiguration.Configuration.UseActivator是使用autofac的注入然後相关的类别HangfireActivatorAllowAllConnectionsFilter如下。

/// <summary>
/// hangfire activator
/// </summary>
public class HangfireActivator : JobActivator
{
    /// <summary>
    /// service provider
    /// </summary>
    private readonly IServiceProvider _provider;

    /// <summary>
    /// Initializes a new instance of the <see cref="HangfireActivator" /> class.
    /// </summary>
    /// <param name="provider">service provider</param>
    public HangfireActivator(IServiceProvider provider)
    {
        _provider = provider;
    }

    /// <summary>
    /// activate job
    /// </summary>
    /// <param name="type">active type</param>
    /// <returns>job instance</returns>
    public override object ActivateJob(Type type)
    {
        return _provider.GetService(type);
    }
}

/// <summary>
/// for hangfire needless authorization
/// </summary>
public class AllowAllConnectionsFilter : IDashboardAuthorizationFilter
{
    /// <summary>
    /// Authorize function
    /// </summary>
    /// <param name="context">dashboard context</param>
    /// <returns>is authorize</returns>
    public bool Authorize(DashboardContext context)
    {
        // Allow outside. You need an authentication scenario for this part.
        // DON'T GO PRODUCTION WITH THIS LINES.
        return true;
    }
}

在注册玩排程之後,接下来要Startup.ConfigureServices内写说要使用排程,这时我们加入以下内容。

services.AddHangfire(x => x.UseMemoryStorage());
services.AddHangfireServer();

这里使用记忆体来放置排程相关资料以及输入参数。到这边为止关於环境的设定就告一段落。接下来要再说明如何建立排程。

建立排程

这边开始说明如何建立一个排程,这部分透过autofac注入後使用上其实相当简单,其实只要建立一个类别并公开一个方法即可,这边要注意的是如果当异常发生时hangfire会有重试的机制,如果不要重试的话要在该方法上加上Attribute即可,如下所示。

[AutomaticRetry(Attempts = 0)]
public void DoJob(DateTime datetime)

还有要注意这边输入的参数要简单,若输入的参数是参考型别然後排程时间又九的状况下有可能该参数被gc了,这样可就gg了。最後来看看如何使用排程。

使用排程

这边常用的设定排程语法有下列两种方式,请看以下范例。

RecurringJob.AddOrUpdate<Schedule>("DoJob",
    x => x.DoJob(),
    Cron.Daily(18));

RecurringJob.AddOrUpdate<Schedule>("DoJob3",
    x => x.DoJob(),
    "0/30 * * * *");

BackgroundJob.Schedule<Schedule>("DoJob2",
    x => x.DoJob(),
    TimeSpan.FromSeconds(3));

首先RecurringJob.AddOrUpdate是定期性的排程,所以这边可以用Cron表达示或是使用Cron来产生Cron表达示,BackgroundJob.Schedule示延迟多久後触一一次性的排程,然後还有一种BackgroundJob.Enqueue是立即触发一次性的排程。这里要注意当排程的参数需要输入时不要以下列方式写。

BackgroundJob.Schedule<Schedule>("DoJob2",
    x => x.DoJob(DateTime.Now),
    TimeSpan.FromSeconds(3));

因为他会把当下时间纪录程每次排程的参数之一,所以如果需要每次排程都需要输入当下时间的话就要建立一个方法是不需要参数输入的,并在该方法内使用DateTime.Now才对。

後记

今天跟着小光还有大头学习如何透过hangfire来设定排程,并且学习到如何建立一个排程以及透过di的方式把需要的元件给注入,希望对大家的dotnetcore排程设计有所帮助,这边还有另外一个Quartz.NET另外一个排程套件,给有兴趣的人看一下。


<<:  Day 22 bert 文字情感分类

>>:  DAY 25 制作表格-添加中文字体

Day2 — 前导:电是如何产生的?从交流到直流

电的产生方式来自於一个简单的事实:电磁感应。在感应线圈里如果磁通量发生变化就会产生电。 虽然在现代这...

Day20. 懂Bootstrap,并让Bootstrap带你上天堂

工程师都有google的习惯,但是 bootstrap 的使用方式不用特别去估狗,基本的用法只要看官...

Day 26 权限宝石:IAM User 建立与使用(下)

今天我们要来介绍多种 IAM User 的创建,那我们开始吧! 透过 Admin 帐号创造 IAM...

Day08:部门与工程团队间协作的技巧(下)

一、前言   承上一篇的部门与工程团队间协作的技巧(上)已有稍微提到一些工程师间的协作软件工具,那如...

@Day24 | C# WixToolset + WPF 帅到不行的安装包 [87分帅的设定页面]

原本 在DemoUse.Installer安装档那边有做自订页面的部分还有选择路径的页面, 我想在开...