.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. 经典Java笔试面试题

    面向对象编程(OOP) Java是一个支持并发.基于类和面向对象的计算机编程语言.下面列出了面向对象软件开发的优点: 代码开发模块化,更易维护和修改. 代码复用. 增强代码的可靠性和灵活性. 增加代码 ...

  2. VMware Tools安装,设置centos全屏、可拖入文件功能

    Mr·Hu原创作品.转载请注明出处http://www.cnblogs.com/huxiuqian/p/7843126.html 由于在VM中使用小屏太不方便,所以进行全屏化,亦可进行文件共享. 1. ...

  3. 简单的python爬虫实例

    目标网站:https://www.quanjing.com/category/1286521/2.html 爬取搜索出来的所有“中东人”的图片: 先看一下源代码,找到存放图片链接的地方,在源代码最下面 ...

  4. scrapy基础知识之 关于爬虫部分一些建议:

    1.尽量减少请求次数,能抓列表页就不抓详情页,减轻服务器压力,程序员都是混口饭吃不容易. 2.不要只看 Web 网站,还有手机 App 和 H5,这样的反爬虫措施一般比较少. 3.实际应用时候,一般防 ...

  5. nio原理和示例代码

    我正在为学习大数据打基础中,为了手撸rpc框架,需要懂得nio的原理,在搞懂nio框架前,我会带着大家手撸一些比较底层的代码,当然今后当我们学会了框架,这些繁琐的代码也就不用写了,但是学一学底层的代码 ...

  6. c++书籍推荐《C++编码规范》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <C++编程规范:101条规则.准则与 实践>:良好的编程规范可以改善软件质量,缩短上市时间,提升团队效率,简化维护工作.在<C++编程规范 ...

  7. <float.h>中DBL_TRUE_MIN的定义和作用

    搬运自己2016年11月22日于SegmentFault发表的文章.链接:https://segmentfault.com/a/1190000007565915 在学习C Prime Plus的过程中 ...

  8. python 3.5学习笔记(第五章)

    本章内容 1.什么是模块 2.模块的导入方法 3.搜索路径 4.重要标准库 一.什么是模块 1.模块本质上是一个以.py 结尾的python文件,包含了python对象定义和python语句. 2.模 ...

  9. web前端笔试篇(一)

    [ 题外话 ]:本博主作为一名准毕业生,即将面临毕业就业问题,即将到大四了,不准备考研的我,那么该去干嘛呢?毫无疑问,那就是实习,那么即使是实习,那么在要想进入自己心仪的企业之前,笔试这一关终究是无法 ...

  10. C#3.0新增功能09 LINQ 标准查询运算符 04 运算

    连载目录    [已更新最新开发文章,点击查看详细] 本篇主要介绍标准查询运算符的常用运算功能. 01 对数据排序 排序操作基于一个或多个属性对序列的元素进行排序. 第一个排序条件对元素执行主要排序. ...