• 在AspNetCore 中执行长任务一个简易的后台服务队列


    背景

    在做离线数据处理时,需要处理的数据量比较大,逻辑很复杂,需要的资源比较多,所以无法立即得到结果,并且客户端也不需要立即得到结果。这种处理任务可以称为 后台任务 或者 “长任务”。
    在 .NetCore 2.0 以前,我们是无法通过Web 服务器来处理后台任务的,要么是控制台程序,要么是windows 后台服务; 但是这种类型的应用互操作性比较差,无法很方便的通过http请求来发送指令,执行操作(当然也可以利用WCF实现,但是会陷入网络通信开发的深坑)。
    在 .NetCore 2.0 以后的版本中,微软提供了IHostedService API ,可以用于开发在WebServer Host 上执行的后台任务,并且可以非常方便的和AspNetCore 框架融合,充分利用Web 请求的互操作性。

    一个 “长任务服务”的设计思路

    • 一个“长任务” 分为执行过程和调度过程
    • 执行过程就是任务的处理逻辑,而调度过程就是启动任务,将任务放到后台队列,当主机有空再处理。
    • 需要知道任务开始、完成情况.

    实现代码

    1. 队列操作接口

     public interface IBackgroundQueue
        {
            void QueueTask(Func<CancellationToken, Task> task);
    
            Task<Func<CancellationToken, Task>> PopQueue(CancellationToken cancellationToken);
        }
    

    2. BackgroundQueue实现

     public class BackgroundQueue : IBackgroundQueue
        {
            private ConcurrentQueue<Func<CancellationToken, Task>> Tasks;
    
            private SemaphoreSlim signal;
    
            public BackgroundQueue()
            {
                Tasks = new ConcurrentQueue<Func<CancellationToken, Task>>();
                signal = new SemaphoreSlim(0);
            }
    
            public async Task<Func<CancellationToken, Task>> PopQueue(CancellationToken cancellationToken)
            {
                await signal.WaitAsync(cancellationToken);
                Tasks.TryDequeue(out var task);
    
                return task;
            }
    
            public void QueueTask(Func<CancellationToken, Task> task)
            {
                Tasks.Enqueue(task);
                signal.Release();
            }
        }
    

    3、使用BackgroundService 类 作为HostedService 的实现

    public class QueueService : BackgroundService
        {
            private IBackgroundQueue _queue;
    
            public QueueService(IBackgroundQueue queue)
            {
                _queue = queue;
            }
            protected override async Task ExecuteAsync(CancellationToken stoppingToken)
            {
                while (stoppingToken.IsCancellationRequested == false)
                {
                    var task = await _queue.PopQueue(stoppingToken);
    
                    await task(stoppingToken);
                }
            }
        }
    

    4. 客户端调用

     public async Task<string> ImportAccountObjectByTimeScale([FromBody] TimeScaleRequest request)
            {
                _queue.QueueTask(async token =>
                {
                      // 将 任务添加到后台队列.
                    await IDataPipeline.Invoke();
                });
                //throw new System.NotImplementedException("");
            }
    
  • 相关阅读:
    1.01与37.8
    CakePHP 2.x CookBook 中文版 第七章 模型 之 检索数据
    CakePHP 2.x CookBook 中文版 第七章 模型
    CakePHP 2.x CookBook 中文版 第七章 模型 之 数据校验
    CakePHP 2.x CookBook 中文版 第五章 控制器 之 请求和响应对象
    CakePHP 2.x CookBook 中文版 第五章 控制器 之 脚手架
    CakePHP 2.x CookBook 中文版 第七章 模型 之 保存数据
    CakePHP 2.x CookBook 中文版 第三章 入门 之 CakePHP 的结构
    Zend Studio 10 phpFormatter 错误的解决
    CakePHP 2.x CookBook 中文版 第三章 入门 之 CakePHP 的文件夹结构
  • 原文地址:https://www.cnblogs.com/aimigi/p/13883876.html
Copyright © 2020-2023  润新知