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

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

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. Spring 框架模块深度解析:核心容器、数据访问、Web 层与其他关键模块

    Spring 可能成为您的所有企业应用程序的一站式商店.但是,Spring 是模块化的,允许您挑选适用于您的模块,而无需引入其他模块.下面的部分提供了 Spring Framework 中所有可用模块 ...

  2. HarmonyOS极客松“上分秘籍”! 高手们顶峰相见!

      HarmonyOS 极客马拉松2023 火热进行中,我们期待与各位开发者相聚一起,践行极客精神,创造无限可能! 我们鼓励各位极客们自由组队,挥洒创意,用HarmonyOS 探索移动应用和服务的更多 ...

  3. k8s之存储卷OpenEBS

    一.OpenEBS简介 OpenEBS 是一种开源云原生存储解决方案,托管于 CNCF 基金会,目前该项目处于沙箱阶段. OpenEBS能够将Kubernetes工作节点上可用的住何存储转换为术卷或分 ...

  4. react native 如何用vs code 进行调试

    前言 以前做react-native 写的文章,在此分享一下. 在react-native 中有两种方式调试,一种是crome 调试,一种是本地调试,接下来介绍的是本地调试. 解决方案 在vs cod ...

  5. -source 1.5 中不支持 diamond 运算符(中文版idea)

    -source 1.5 中不支持 diamond 运算符(中文版idea) 将idea中的各个部分的jdk设为8即可,中文版的如下 1.文件-设置 2.项目上右击-打开模块设置 模块中每一个都要确认是 ...

  6. 力扣1127(MySQL)-用户购买平台(困难)

    题目: 支出表: Spending 这张表记录了用户在一个在线购物网站的支出历史,该在线购物平台同时拥有桌面端('desktop')和手机端('mobile')的应用程序.这张表的主键是 (user_ ...

  7. 力扣578(MySQL)-查询回答率最高的问题(中等)

    题目: 从 survey_log 表中获得回答率最高的问题,survey_log 表包含这些列:id, action, question_id, answer_id, q_num, timestamp ...

  8. 力扣128(java&python)-最长连续序列(中等)

    题目: 给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度. 请你设计并实现时间复杂度为 O(n) 的算法解决此问题. 示例 1: 输入:nums = ...

  9. API 开发的后盾:平台工程提供强力动态支持

    过去几年,开发团队一直在发展传统的 DevOps.一些开发人员认为,CloudOps 或 DeploymentOps 等新实践的兴起将会导致回到孤岛问题.其他人则不愿意在承担所有其他职责之外构建.部署 ...

  10. 2022飞天技术峰会:硬之城如何基于 SAE 打造数智化电子工业互联网平台

    简介: 全球数字化时代已经到来,数字经济正推动生产方式.生活方式和治理方式的深刻变化,成为重组全球要素资源,重塑经济结构,改变全球竞争格局的关键力量. 本文根据硬之城 CEO 李六七先生在峰会上的分享 ...