.net core 基于 IHostedService 实现定时任务

Intro

从 .net core 2.0 开始,开始引入 IHostedService,可以通过 IHostedService 来实现后台任务,但是只能在 WebHost 的基础上使用。从 .net core 2.1 开始微软引入通用主机(Generic Host),使得我们可以在不使用 Web 的情况下,也可以使用 IHostedService 来实现 定时任务/Windows服务/后台任务,并且引入了一个 BackgroundService 抽象类来更方便的创建后台任务。

IHostedService

IHostedService 后台任务的执行与应用程序(就此而言,为主机或微服务)的生存期相协调。 当应用程序启动时注册任务,当应用程序关闭时,有机会执行某些正常操作或清理。

始终可以启动后台线程来运行任何任务,而无需使用 IHostedService。 不同之处就在于应用的关闭时间,此时会直接终止线程,而没有机会执行正常的清理操作。

当注册 IHostedService 时,.NET Core 会在应用程序启动和停止期间分别调用 IHostedService 类型的 StartAsync()StopAsync() 方法。 具体而言,即在服务器已启动并已触发 IApplicationLifetime.ApplicationStarted 后调用 start。

namespace Microsoft.Extensions.Hosting
{
//
// Summary:
// Defines methods for objects that are managed by the host.
public interface IHostedService
{
//
// Summary:
// Triggered when the application host is ready to start the service.
Task StartAsync(CancellationToken cancellationToken);
//
// Summary:
// Triggered when the application host is performing a graceful shutdown.
Task StopAsync(CancellationToken cancellationToken);
}
}

可以从头开始创建自定义托管服务类并实现 IHostedService,因为在使用 .NET Core 2.0 时需执行这些操作。

但是,由于大多数后台任务在取消令牌管理和其他典型操作方面都有类似的需求,因此 .net core 2.1 有一个非常方便且可以从中进行派生的抽象基类,BackgroundService 定义如下:

// Copyright (c) .NET Foundation. Licensed under the Apache License, Version 2.0.
/// <summary>
/// Base class for implementing a long running <see cref="IHostedService"/>.
/// </summary>
public abstract class BackgroundService : IHostedService, IDisposable
{
private Task _executingTask;
private readonly CancellationTokenSource _stoppingCts =
new CancellationTokenSource(); protected abstract Task ExecuteAsync(CancellationToken stoppingToken); public virtual Task StartAsync(CancellationToken cancellationToken)
{
// Store the task we're executing
_executingTask = ExecuteAsync(_stoppingCts.Token); // If the task is completed then return it,
// this will bubble cancellation and failure to the caller
if (_executingTask.IsCompleted)
{
return _executingTask;
} // Otherwise it's running
return Task.CompletedTask;
} public virtual async Task StopAsync(CancellationToken cancellationToken)
{
// Stop called without start
if (_executingTask == null)
{
return;
} try
{
// Signal cancellation to the executing method
_stoppingCts.Cancel();
}
finally
{
// Wait until the task completes or the stop token triggers
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
} } public virtual void Dispose()
{
_stoppingCts.Cancel();
}
}

实现一个的后台定时任务

基于上面的信息,我们可以基于 IHostedService 实现一个简单的后台定时任务服务,

public abstract class ScheduledService : IHostedService, IDisposable
{
private readonly Timer _timer;
private readonly TimeSpan _period;
protected readonly ILogger Logger; protected ScheduledService(TimeSpan period, ILogger logger)
{
Logger = logger;
_period = period;
_timer = new Timer(Execute, null, Timeout.Infinite, 0);
} public void Execute(object state = null)
{
try
{
Logger.LogInformation("Begin execute service");
ExecuteAsync().Wait();
}
catch (Exception ex)
{
Logger.LogError(ex, "Execute exception");
}
finally
{
Logger.LogInformation("Execute finished");
}
} protected abstract Task ExecuteAsync(); public virtual void Dispose()
{
_timer?.Dispose();
} public Task StartAsync(CancellationToken cancellationToken)
{
Logger.LogInformation("Service is starting.");
_timer.Change(TimeSpan.FromSeconds(SecurityHelper.Random.Next(10)), _period);
return Task.CompletedTask;
} public Task StopAsync(CancellationToken cancellationToken)
{
Logger.LogInformation("Service is stopping."); _timer?.Change(Timeout.Infinite, 0); return Task.CompletedTask;
}
}

基于上面这个基于Timer实现的后台定时任务类实现一个定时任务:

public class RemoveOverdueReservationService : ScheduledService
{
public RemoveOverdueReservationService(ILogger<RemoveOverduedReservtaionService> logger) : base(TimeSpan.FromDays(1), logger)
{ } protected override Task ExecuteAsync()
{
return DependencyResolver.Current.TryInvokeServiceAsync<IEFRepository<ReservationDbContext, Reservation>>(reservationRepo =>
{
return reservationRepo.DeleteAsync(reservation => reservation.ReservationStatus == 0 && (reservation.ReservationForDate < DateTime.Today.AddDays(-3)));
});
}
}

这个类实现的是每天执行一次,删除三天前状态为待审核的预约,完整实现代码:https://github.com/WeihanLi/ActivityReservation/blob/dev/ActivityReservation.Helper/Services/RemoveOverduedReservtaionService.cs

在程序启动的时候注册服务:

services.AddHostedService<RemoveOverduedReservtaionService>();

执行日志:

通过日志可以看到我们的定时任务确实是每天执行一次,这样我们的定时任务就算是简单的完成了。

Reference

.net core 基于 IHostedService 实现定时任务的更多相关文章

  1. ASP.NET Core 基于JWT的认证(二)

    ASP.NET Core 基于JWT的认证(二) 上一节我们对 Jwt 的一些基础知识进行了一个简单的介绍,这一节我们将详细的讲解,本次我们将详细的介绍一下 Jwt在 .Net Core 上的实际运用 ...

  2. ASP.NET Core 基于JWT的认证(一)

    ASP.NET Core 基于JWT的认证(一) Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计 ...

  3. Asp.Net Core基于JWT认证的数据接口网关Demo

    近日,应一位朋友的邀请写了个Asp.Net Core基于JWT认证的数据接口网关Demo.朋友自己开了个公司,接到的一个升级项目,客户要求用Aps.Net Core做数据网关服务且基于JWT认证实现对 ...

  4. .net core 基于Claim登录验证

    网站,首先需要安全,实现安全就必须使用登录验证,.net core 基于Claim登录验证就很简单使用. Claim是什么,可以理解为你的身份证的中的名字,性别等等的每一条信息,然后Claim组成一个 ...

  5. 并发编程概述 委托(delegate) 事件(event) .net core 2.0 event bus 一个简单的基于内存事件总线实现 .net core 基于NPOI 的excel导出类,支持自定义导出哪些字段 基于Ace Admin 的菜单栏实现 第五节:SignalR大杂烩(与MVC融合、全局的几个配置、跨域的应用、C/S程序充当Client和Server)

    并发编程概述   前言 说实话,在我软件开发的头两年几乎不考虑并发编程,请求与响应把业务逻辑尽快完成一个星期的任务能两天完成绝不拖三天(剩下时间各种浪),根本不会考虑性能问题(能接受范围内).但随着工 ...

  6. Net Core基于TopShelf程序运行于服务模式

    目录 Net Core基于TopShelf程序运行于服务模式 1 背景 2 优势 2.1 服务模式可设置重启条件 2.2 避免误操作 3.使用 3.1 GUI方式安装Topshelf包 4 配置 5 ...

  7. ASP.NET Core基于K8S的微服务电商案例实践--学习笔记

    摘要 一个完整的电商项目微服务的实践过程,从选型.业务设计.架构设计到开发过程管理.以及上线运维的完整过程总结与剖析. 讲师介绍 产品需求介绍 纯线上商城 线上线下一体化 跨行业 跨商业模式 从0开始 ...

  8. .Net Core 基于CAP框架的事件总线

    .Net Core 基于CAP框架的事件总线 CAP 是一个在分布式系统中(SOA,MicroService)实现事件总线及最终一致性(分布式事务)的一个开源的 C# 库,她具有轻量级,高性能,易使用 ...

  9. Spring基于SchedulingConfigurer实现定时任务

    Spring 基于 SchedulingConfigurer 实现定时任务,代码如下: import org.springframework.scheduling.annotation.Schedul ...

随机推荐

  1. 二进制mariadb多实例

    实验环境: centos7.6 :IP: 192.168.99.110 1.首先下载二进制的压缩包,解压到一个指定的目录/hx/下 [root@centos7 hx]#tar xf mariadb-1 ...

  2. 【HDU - 2102】A计划(bfs)

    -->A计划 Descriptions: 可怜的公主在一次次被魔王掳走一次次被骑士们救回来之后,而今,不幸的她再一次面临生命的考验.魔王已经发出消息说将在T时刻吃掉公主,因为他听信谣言说吃公主的 ...

  3. vue.js 解决跨域问题

    我们调试vue.js代码的时候一般都用chrome, 下载插件 进入chrome应用商店 搜索 重启chrome就可以解决跨域问题

  4. Linux权限_用户_和用户组

    Linux中用户UID就判断操作系统中用户的身份. Centos7.x: 0:超级管理员 1-999:系统用户(包含Linux中自带服务) 1000以上   普通用户 Centos6.x : Root ...

  5. SpringBoot事物Transaction实战讲解教程

    前言 本篇文章主要介绍的是SpringBoot的事物Transaction使用的教程. SpringBoot Transaction 说明:如果想直接获取工程那么可以直接跳到底部,通过链接下载工程代码 ...

  6. Bzoj 2318 Spoj4060 game with probability Problem

    2318: Spoj4060 game with probability Problem Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 524  Sol ...

  7. Balking设计模式

    import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayLi ...

  8. idea万能快捷键(alt enter),你不知道的17个实用技巧!!!

    说明 IDEA里有一个万能快捷键(alt enter),功能非常强大,同一个快捷键,可以根据不同的语境提示你不同的操作, 很多人可能还不了解这些功能,在处理代码的时候还手动处理,了解这些技巧之后,你编 ...

  9. R018---RPA是什么东东?

    1.缘起 这个问题,很多文章回答过,一直想站在客户角度写个答案,今天正好. 2.RPA的名字  RPA是英文Robotic Process Automation的缩写,中文爱翻译为“流程自动化机器人” ...

  10. Java虚拟机知识点【内存】

    运行时数据区 程序计数器(Program Counter)   每个线程独占自己的程序计数器.如果当前执行的方式不是native的,那程序计数器保存JVM正在执行的字节码指令的地址,如果是native ...