很多时候我们都会使用后台定时任务,但有些任务不需要定时执行,只需要请求到来时执行一次,比如请求服务器到某个地方同步数据,但请求不需要等数据同步完成再响应。这时候就可以使用排队的后台任务。

基本原理是用一个队列保存任务委托,然后用一个后台定时任务依次执行队列中的委托。

MSDN上把源代码都写好了

 1 public interface IBackgroundTaskQueue
2 {
3 ValueTask QueueBackgroundWorkItemAsync(Func<CancellationToken, ValueTask> workItem);
4
5 ValueTask<Func<CancellationToken, ValueTask>> DequeueAsync(
6 CancellationToken cancellationToken);
7 }
8
9 public class BackgroundTaskQueue : IBackgroundTaskQueue
10 {
11 private readonly Channel<Func<CancellationToken, ValueTask>> _queue;
12
13 public BackgroundTaskQueue(int capacity)
14 {
15 // Capacity should be set based on the expected application load and
16 // number of concurrent threads accessing the queue.
17 // BoundedChannelFullMode.Wait will cause calls to WriteAsync() to return a task,
18 // which completes only when space became available. This leads to backpressure,
19 // in case too many publishers/calls start accumulating.
20 var options = new BoundedChannelOptions(capacity)
21 {
22 FullMode = BoundedChannelFullMode.Wait
23 };
24 _queue = Channel.CreateBounded<Func<CancellationToken, ValueTask>>(options);
25 }
26
27 public async ValueTask QueueBackgroundWorkItemAsync(
28 Func<CancellationToken, ValueTask> workItem)
29 {
30 if (workItem == null)
31 {
32 throw new ArgumentNullException(nameof(workItem));
33 }
34
35 await _queue.Writer.WriteAsync(workItem);
36 }
37
38 public async ValueTask<Func<CancellationToken, ValueTask>> DequeueAsync(
39 CancellationToken cancellationToken)
40 {
41 var workItem = await _queue.Reader.ReadAsync(cancellationToken);
42
43 return workItem;
44 }
45 }

BackgroundTaskQueue

 1 public class QueuedHostedService : BackgroundService
2 {
3 private readonly ILogger<QueuedHostedService> _logger;
4
5 public QueuedHostedService(IBackgroundTaskQueue taskQueue,
6 ILogger<QueuedHostedService> logger)
7 {
8 TaskQueue = taskQueue;
9 _logger = logger;
10 }
11
12 public IBackgroundTaskQueue TaskQueue { get; }
13
14 protected override async Task ExecuteAsync(CancellationToken stoppingToken)
15 {
16 _logger.LogInformation(
17 $"Queued Hosted Service is running.{Environment.NewLine}" +
18 $"{Environment.NewLine}Tap W to add a work item to the " +
19 $"background queue.{Environment.NewLine}");
20
21 await BackgroundProcessing(stoppingToken);
22 }
23
24 private async Task BackgroundProcessing(CancellationToken stoppingToken)
25 {
26 while (!stoppingToken.IsCancellationRequested)
27 {
28 var workItem =
29 await TaskQueue.DequeueAsync(stoppingToken);
30
31 try
32 {
33 await workItem(stoppingToken);
34 }
35 catch (Exception ex)
36 {
37 _logger.LogError(ex,
38 "Error occurred executing {WorkItem}.", nameof(workItem));
39 }
40 }
41 }
42
43 public override async Task StopAsync(CancellationToken stoppingToken)
44 {
45 _logger.LogInformation("Queued Hosted Service is stopping.");
46
47 await base.StopAsync(stoppingToken);
48 }
49 }

QueuedHostedService

services.AddHostedService<QueuedHostedService>();
services.AddSingleton<IBackgroundTaskQueue>(ctx =>
{
int queueCapacity = 100;
return new BackgroundTaskQueue(queueCapacity);
});

然后在控制器的方法中向队列中添加委托即可

await _backgroundTaskQueue.QueueBackgroundWorkItemAsync(async token =>
{
await SyncPersonPhotoAsync(persons);
});

webapi动态创建后台任务(使用排队的后台任务)的更多相关文章

  1. 动态创建Lambda表达式实现高级查询

    需求简介 最近这几天做的东西总算是回归咱的老本行了,给投资管理项目做一个台账的东西,就是类似我们的报表.其 中有一个功能是一个高级查询的需求,在查询条件方面大概有7.8个查询条件.需求就是如果一个条件 ...

  2. k8s-jenkins x CI/CD 动态创建slave---01

    jenkins CI/CD(动态创建slave)简述: 由于之前管理kubernetes集群应用发布,用的是Gitlab-CI,用作开发环境管理还可以,生产环境管理发布,缺点太多,打包速度很慢.研究新 ...

  3. JavaScript dom 动态创建标记

    此前的大多数DOM都是用来查找元素,getElementById和getElementsByTagName都可以方便快捷的找到文档中的某个或者某些特定的元素节点,这些元素随后可以用诸如setAttri ...

  4. ios动态创建类Class

    [Objective-C Runtime动态加载]---动态创建类Class 动态创建类Class,动态添加Class成员变量与成员函数,动态变量赋值与取值,动态函数调用等方法 a.使用objc_al ...

  5. winform 用户控件、 动态创建添加控件、timer控件、控件联动

    用户控件: 相当于自定义的一个panel 里面可以放各种其他控件,并可以在后台一下调用整个此自定义控件. 使用方法:在项目上右键.添加.用户控件,之后用户控件的编辑与普通容器控件类似.如果要在后台往窗 ...

  6. python动态创建类的声明

    动态创建类的声明 使用内置函数type,原型:class type(name, bases, dict)name是类的名字,相当于__class__bases是类的基类,元组,可以有多个基类,但是基类 ...

  7. Python 动态创建函数【转】

    知乎上也有相似的问题 偶然碰到一个问题,初想是通过动态创建Python函数的方式来解决,于是调研了动态创建Python函数的方法. 定义lambda函数 在Python中定义lambda函数的写法很简 ...

  8. WinForm用户控件、动态创建添加控件、timer控件--2016年12月12日

    好文要顶 关注我 收藏该文 徐淳 关注 - 1 粉丝 - 3       0 0     用户控件: 通过布局将多个控件整合为一个控件,根据自己的需要进行修改,可对用户控件内的所有控件及控件属性进行修 ...

  9. 动态创建DAL层类的实例

    为了可扩展性,方便以后对于代码的修改维护,使用动态创建DAL层对象. 1.首先在webconfig中的configuration下添加配置项 <appSettings> <add k ...

  10. [转]android:动态创建多个按钮 及 批量设置监听

    之前投机取巧,先创建好多个按钮,再根据需要的数量进行部分隐藏,不过还是逃不过呀. 这样根本无法批量地 findId,批量地 设置监听. 所以今天还是认认真真地研究回“动态创建按钮”,终于,通过不断尝试 ...

随机推荐

  1. C语言 05 变量与常量

    变量 变量就像在数学中学习的 x,y 一样,可以直接声明一个变量,并利用这些变量进行基本的运算,声明变量的格式为: 数据类型 变量名称 = 初始值;(其中初始值可以不用在定义变量时设定) = 是赋值操 ...

  2. Rust——生命周期

    简而言之,即引用的有效作用域:一般情况下编译器会自动检查推导,但是当多个声明周期存在时,编译器无法推导出某个引用的生命周期,需要手动标明生命周期. 悬垂指针 悬垂指针是指一个指针指向了被释放的内存或者 ...

  3. 重新点亮shell————测试命令[六]

    前言 我们写好脚本之后希望有一个测试. 正文 介绍一下exit,如果exit 0,那么表示正常退出. 如果exit 10,也就是非0,那么就是异常退出. 然后这个test 标准为[]和 [[]]这样子 ...

  4. 力扣540(java&python)-有序数组中的单一元素(中等)

    题目: 给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次. 请你找出并返回只出现一次的那个数. 你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间 ...

  5. Koordinator v0.7: 为任务调度领域注入新活力

    简介: 在这个版本中着重建设了机器学习.大数据场景需要的任务调度能力,例如 Coscheduling.ElasticQuota 和精细化的 GPU 共享调度能力.并在调度问题诊断分析方面得到了增强,重 ...

  6. 动态尺寸模型优化实践之Shape Constraint IR Part II

    简介: 在本系列分享中我们将介绍BladeDISC在动态shape语义下做性能优化的一些实践和思考.本次分享的是我们最近开展的有关shape constraint IR的工作,Part II 中我们将 ...

  7. Flink 作为现代数据仓库的统一引擎:Hive 集成生产就绪!

    在2020年,你的数据仓库和基础设施需要满足哪些需求? 我们总结了几下几点: 首先,当下的企业正快速转向更实时化的模式,这要求企业具备对线上流式数据进行低延迟处理的能力,以满足实时(real-time ...

  8. PolarDB-X 高可用存储服务: 基于 X-Paxos 一致性协议

    简介: 摘自刘永平(慕少)阿里云 PolarDB-X 技术专家在PolarDB-X | 新品发布会中的讲解内容. 了解更多PolarDB-X 内容:https://developer.aliyun.c ...

  9. 混合云K8s容器化应用弹性伸缩实战

    简介: 混合云K8s容器化应用弹性伸缩实战 1. 前提条件 本最佳实践的软件环境要求如下:应用环境:①容器服务ACK基于专有云V3.10.0版本.②公共云云企业网服务CEN.③公共云弹性伸缩组服务ES ...

  10. dotnet 8 破坏性改动 在 AssemblyInformationalVersionAttribute 添加上 git 的 commit 号

    我在一个 WPF 项目里面,在界面显示应用的版本号,更新到 dotnet 8 的 SDK 之后,发现我的界面布局损坏了.本质上这个破坏性改动和 WPF 没有什么关系,是 dotnet 的 SDK 或编 ...