.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. VMware Tools安装,设置centos全屏、可拖入文件功能

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

  2. Java多线程学习(吐血超详细总结)

    Java多线程学习(吐血超详细总结) 林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 写在前面的话:此文只能说是java多线程的一个入门,其实 ...

  3. 使用pymysql操作mysql数据库

    PyMySQL的安装和连接 PyMySQL的安装 python3. -m pip install pymysql python连接数据库 import pymysql # 创建连接 conn = py ...

  4. JUnit-4.13使用报java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing错误

    今天重新复习spring的时候,调用Junit架包来进行测试,进入其官网  https://junit.org/junit5/,点击右上角的Junit4进行查看 2.出现了的页面是这个样子 我把这个页 ...

  5. Java Volatile 关键字详解

    原文链接:https://www.cnblogs.com/zhengbin/p/5654805.html 一.基本概念 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性 ...

  6. scrapy基础知识之下载中间件使用案例:

    1. 创建middlewares.py文件. Scrapy代理IP.Uesr-Agent的切换都是通过DOWNLOADER_MIDDLEWARES进行控制,我们在settings.py同级目录下创建m ...

  7. Linux命令及安装

    1.三大操作系统 1.Unix Solaris(SUN) IOS(Aplle移动端) Mas OS(Aplle平板,电脑端) 2.Windows XP win7 win8 win10 3.Linux ...

  8. [网络协议]UDP实现的可靠协议

    UDP实现的可靠协议,基本都会对TCP的某一部分进行加强,另外一部分进行削弱.因为: “实时性+可靠性+公平性” 三者不能同时保证,因此可以牺牲TCP的局部公平性来换取更好的实时性,或者更浪费点带宽, ...

  9. 嵊州D3T2 福尔贝斯太太的快乐夏日 summer

    宗教,或是无节制的自由主义,是致人腐化的毒剂. 现在,一个人要经历 n 个事件,编号为 1 ∼ n. 经历 x 号事件,他的危险值就会增加 x. 一开始他的危险值是 0. 当一个人的危险值大于 0 且 ...

  10. findBugs英文代号的对照表

    findBugs错误英文翻译rule.findbugs.IMSE_DONT_CATCH_IMSE.name=不良实践 - 捕获可疑IllegalMonitorStateException rule.f ...