webapi动态创建后台任务(使用排队的后台任务)

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

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

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);
});

 

posted @   ggtc  阅读(97)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
//右下角目录
点击右上角即可分享
微信分享提示