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

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

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. 基于ArkUI框架开发-ImageKnife渲染层重构

      ImageKnife是一款图像加载缓存库,主要功能特性如下: ●支持内存缓存,使用LRUCache算法,对图片数据进行内存缓存. ●支持磁盘缓存,对于下载图片会保存一份至磁盘当中. ●支持进行图片 ...

  2. 开源图形驱动在OpenHarmony上的使用和落地

      本文转载自 OpenHarmony TSC 官方微信公众号<峰会回顾第10期 | 开源图形驱动在OpenHarmony上的使用和落地> 演讲嘉宾 | 黄   然 回顾整理 | 廖    ...

  3. Prometheus AlertManager 生产实践-直接根据 to_email label 发 alert 到对应邮箱

    概述 通过之前的文章 - Prometheus Alertmanager 生产配置趟过的坑总结, 我们已经知道 AlertManager 作为告警平台,是非常强大的,可以去重 (deduplicati ...

  4. C 语言宏 + 内联汇编实现 MIPS 系统调用

    目录 内联汇编 宏函数 宏定义 Syscall 内联汇编 编译测试 笔者最近作业要求练习 MIPS 汇编,熟悉 MIPS 汇编代码与 C 语言代码的对应关系.然而 SPIM/MARS 仿真器不能链接共 ...

  5. ICMP 概念

    前言 打算从新整理网络这一块,那么我先把概念整理下来. 正文 ICMP是ip的一个组成.他传递差错报文以及其他需要注意的信息.主要用于反馈一些网络传输的问题.因为ip协议很容易丢包,那么icmp可以告 ...

  6. c# 后端与前端时间戳的转换

    C# DateTime与时间戳转换 C# DateTime与时间戳的相互转换,包括JavaScript时间戳和Unix的时间戳. 1. 什么是时间戳 首先要清楚JavaScript与Unix的时间戳的 ...

  7. [FAQ] 如何避免过度依赖百度, 甚至超越百度

    查找信息,你不依赖百度,势必要依赖其它. 那么如何超越百度搜索,也必须要站在巨人的肩膀上. 搜索市场已有不少巨头,最简单的超越办法是:站在所有巨人的肩膀上. Other:搜索的超越 Link:http ...

  8. [FAQ] FinalCutPro 视频背景加模糊效果

    1. 时间轴右上方,找到 倒数第二个 "显示或隐藏效果浏览器",里面有一个 "模糊" 效果: 2. "模糊"效果中的 "高斯曲线& ...

  9. [FAQ] uni-app 不支持 v-cloak 情况下如何处理 v-if 页面闪烁问题

    在 Vue 中存在使用 v-if 决定元素显示隐藏的时候,会出现页面闪烁,那么当然 uni-app 中也存在了. 如果编译完后,需要满足 js 的某个条件才隐藏,页面元素必然会有闪烁的情况. 所以解决 ...

  10. MSIL 静态类在 IL 定义上和非静态类的差别

    本文来聊聊 MSIL 的基础知识,给一个 C# 的类标记了 static 之后和标记 static 之前,生成这个类的 IL 代码有什么不同 如以下的代码是一个默认的控制台程序 class Progr ...