后台定时任务 Hangfire

[Hangfire]最大特点在于内置提供集成化的控制台(无需自行定制开发和管理基于Windows Service后台任务执行器),方便后台查看及监控。包含三大核心组件:客户端、持久化存储、服务端。官方文档:http://docs.hangfire.io/en/latest/

客户端:
[fire-and-forget](基于队列的任务处理)
var client = new BackgroundJobClient();
client.Enqueue(() => Console.WriteLine("Easy!"));

该Enqueue方法不会立即调用目标方法,而是运行以下步骤:
1序列化方法信息及其所有参数。
2根据序列化信息创建新的后台作业。
3将后台作业保存到持久存储。
4将后台作业排入队列。
在任务被持久化到数据库之后,Hangfire服务端立即从数据库获取相关任务并装载到相应的Job Queue下,在没有异常的情况下仅处理一次,若发生异常,提供重试机制,异常及重试信息都会被记录到数据库中,通过Hangfire控制面板可以查看到这些信息。

[Delayed jobs](在一段时间后执行调用)
var client = new BackgroundJobClient();
client.Delay(() => Console.WriteLine("Reliable!"), TimeSpan.FromDays(1));
BackgroundJob.Schedule(
() => Console.WriteLine("Hello, world"),
TimeSpan.FromDays(1));
[Hangfire Server会]定期检查计划,将计划的作业排入队列,允许工作人员执行它们。默认情况下,检查间隔等于15s,但您可以通过在传递给构造函数的选项上设置SchedulePollingInterval属性来更改它:15 seconds``BackgroundJobServer
var options = new BackgroundJobServerOptions
{
SchedulePollingInterval = TimeSpan.FromMinutes(1)
};
var server = new BackgroundJobServer(options);

定时任务执行(Recurring jobs)
定时(循环)任务代表可以重复性执行多次,支持CRON表达式:
RecurringJob.AddOrUpdate(
() => Console.WriteLine("Recurring!"),Cron.Daily);
此行在持久存储中创建新条目。Hangfire Server中的一个特殊组件以基于分钟的间隔检查重复作业,然后将它们列为“即发即弃”作业。
每个定期作业都有自己的唯一标识符。在前面的示例中,它是使用给定调用表达式的类型和方法名称隐式生成的,本RecurringJob类包含需要一个明确定义的作业标识符重载。
RecurringJob.AddOrUpdate("some-id", () => Console.WriteLine(), Cron.Hourly);

移除操作重复性作业
可以通过调用RemoveIfExists方法删除现有的定期作业。当没有这样的重复工作时,它不会抛出异常。
RecurringJob.RemoveIfExists("some-id");
如果要立即运行定期作业,要调用Trigger方法。手动触发调用的信息不会记录在定期作业本身中,并且不会从此次运行中重新计算其下一个执行时间。例如,如果有一个星期三运行的每周作业,并且在星期五手动触发它,它将在接下来的星期三运行。
RecurringJob.Trigger("some-id");
RecurringJob管理类
var manager = new RecurringJobManager();
manager.AddOrUpdate("some-id", Job.FromExpression(() => Method()), Cron.Yearly());

延续性任务执行(Continuations)
延续性任务类似于.NET中的Task,可以在第一个任务执行完之后紧接着再次执行另外的任务:
BackgroundJob.ContinueWith(
jobId,
() => Console.WriteLine("Continuation!"));

传递依赖关系:
Hangfire允许您在后台调用实例方法。
实例:有以下类使用某种类DbContext来访问数据库和EmailService发送电子邮件
public class EmailSender
{
public void Send(int userId, string message)
{
var dbContext = new DbContext();
var emailService = new EmailService();
// Some processing logic
}
}
要Send在后台调用该方法,请使用以下Enqueue方法重写:
BackgroundJob.Enqueue(x => x.Send(13, "Hello!"));
当worker确定需要调用实例方法时,它首先使用当前JobActivator类实例创建给定类的实例。默认情况下,它使用Activator.CreateInstance可以使用其默认构造函数创建类实例的方法,所以让我们添加它:
public class EmailSender
{
private IDbContext _dbContext;
private IEmailService _emailService;

public EmailSender()
{
    _dbContext = new DbContext();
    _emailService = new EmailService();
}
// ...

}
不使用默认无参构造函数的情况下还可以使用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会保留后台作业以及与持久存储中的处理相关的其他信息。持久性有助于后台作业在应用程序重新启动,服务器重新启动等时继续存在。这是使用CLR的线程池Hangfire执行后台作业之间的主要区别。支持不同的存储后端:

  • [SQL Azure,SQL Server 2008 R2](以及任何版本的更高版本,包括Express)
  • [Redis]
    可以使用[MSMQ]或RabbitMQ为SQL Server存储提供强大的功能,以降低处理延迟。
    GlobalConfiguration.Configuration.UseSqlServerStorage("db_connection");

服务器:
后台作业由[Hangfire Server]处理。它被实现为一组专用(非线程池)后台线程,用于从存储中获取作业并处理它们。服务器还负责保持存储清洁并自动删除旧数据。

在客户端的执行BackgroundJob.Enqueue方法立即返回给调用者。[Hangfire Server的] Hangfire组件检查持久存储以查找排队的后台作业,并以可靠的方式执行它们。
排队作业由专用的工作线程池处理。每个worker调用以下过程:

  1. 获取下一个工作并将其隐藏在其他工作人员之外
  2. 执行作业及其所有扩展过滤器。
  3. 从队列中删除作业。

using (new BackgroundJobServer())
{
Console.WriteLine("Hangfire Server started. Press ENTER to exit...");
Console.ReadLine();
}
服务并行度配置
后台作业由在Hangfire Server子系统内运行的专用工作线程池处理。启动后台作业服务器时,它会初始化池并启动固定数量的工作程序。您可以通过将值传递给UseHangfireServer方法来指定其编号。
var options = new BackgroundJobServerOptions { WorkerCount = Environment.ProcessorCount * 5 };
app.UseHangfireServer(options);
如果在Windows服务或控制台应用程序中使用Hangfire,请执行以下操作:
var options = new BackgroundJobServerOptions
{
// This is the default value
WorkerCount = Environment.ProcessorCount * 5
};
var server = new BackgroundJobServer(options);

配置作业队列
Hangfire可以处理多个队列。如果您想要优先处理作业或在服务器之间拆分处理),可以将作业放入不同的队列(队列名称参数必须仅包含小写字母,数字和下划线字符),在方法上使用QueueAttribute类:
[Queue("critical")]
public void SomeMethod() { }
BackgroundJob.Enqueue(() => SomeMethod());
在服务端更新BackgroundJobServer配置,顺序很重要,将首先从关键队列中获取作业,然后从默认队列中获取作业。
var options = new BackgroundJobServerOptions
{
Queues = new[] { "critical", "default" }
};
app.UseHangfireServer(options);
// or
using (new BackgroundJobServer(options)) { /* ... */ }

异常处理:
Hangfire的 AutomaticRetryAttribute`可以拦截并更改初始管道。此过滤器全局应用于所有方法,默认情况下有10次重试尝试。因此,如果出现异常,方法将被重试,并且每次尝试失败时都会收到警告日志消息。如果重试尝试超过其最大值,则作业将移至该Failed状态(带有错误日志消息);如果不希望重试作业,请放置一个显式属性,其中包含0个最大重试次数值:
[AutomaticRetry(Attempts = 0)]
public void BackgroundMethod()
{}
使用相同的方法限制尝试不同值的次数。如果要更改默认全局值,请添加新的全局过滤器:
GlobalJobFilters.Filters.Add(new AutomaticRetryAttribute { Attempts = 5 });

官方教程:
http://docs.hangfire.io/en/latest/tutorials/index.html

你可能感兴趣的:(后台定时任务 Hangfire)