.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. Singleton and Prototype Bean Scope in Spring

    Scope描述的是Spring容器如何新建Bean的实例的. 1> Singleton: 一个Spring容器只有一个Bean的实例,此为Spring的默认配置,全容器共享一个实例. 2> ...

  2. SQL Server温故系列(3):SQL 子查询 & 公用表表达式 CTE

    1.子查询 Subqueries 1.1.单行子查询 1.2.多行子查询 1.3.相关子查询 1.4.嵌套子查询 1.5.子查询小结及性能问题 2.公用表表达式 CTE 2.1.普通公用表表达式 2. ...

  3. Android 蓝牙开发(2)——低功耗蓝牙

    低功耗蓝牙官方文档 本文章是参考官网,然后加入自己实践中的理解完成!没有看上一篇的读者,可以先阅读一下前一篇,这是一个系列. 官网地址:https://developer.android.com/gu ...

  4. 什么是JS跨域请求

    这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...

  5. 屏蔽谷歌浏览器"请停用以开发者模式运行的扩展程序"提示

    目标: 对于强迫症患者那是相当难受~~~ 解决方案: 1:进入chrome://extensions/ 右上角开启开发者模式 点击打包扩展程序: 2:扩展程序目录为选择插件(*.crx解压后)的根目录 ...

  6. django基础知识之自连接:

    自连接 对于地区信息,属于一对多关系,使用一张表,存储所有的信息 类似的表结构还应用于分类信息,可以实现无限级分类 新建模型AreaInfo,生成迁移 class AreaInfo(models.Mo ...

  7. Vue快速学习_第二节

    表单输入绑定(v-model) v-model 指令在表单 <input>.<textarea> 及 <select> 元素上创建双向数据绑定(注意只在表单这几个可 ...

  8. 通讯(tarjan缩点)(20190716NOIP模拟测试4)

    B. 通讯   题目类型:传统 评测方式:文本比较  内存限制:256 MiB 时间限制:1000 ms 标准输入输出 题目描述 “这一切都是命运石之门的选择.” 试图研制时间机器的机关SERN截获了 ...

  9. Hadoop现在怎么样了?

    之前我们提到大数据的时候就会提到Hadoop,Hadoop是大数据的基础框架,是大数据技术的代表.提到HDFS.MapReduce.Yarn,提到HBase.Hive.TEZ等Hadoop生态圈中的一 ...

  10. python爬虫笔记之用cookie访问需要登录的网站

     目标:用cookie访问一个需要登录的网站 如图,直接访问会跳转到登录页面,提示登录. 运行结果: 直接在浏览器上输入该url,网站立马跳转到登录页面.  方法: 1.先手动登录,通过抓包获取coo ...