Alternative solution to HostingEnvironment.QueueBackgroundWorkItem in .NET Core

后端 未结 6 1853
栀梦
栀梦 2020-12-23 11:04

We are working with .NET Core Web Api, and looking for a lightweight solution to log requests with variable intensity into database, but don\'t want client\'s to wait for th

6条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-23 11:37

    I know this is a little late, but we just ran into this issue too. So after reading lots of ideas, here's the solution we came up with.

        /// 
        /// Defines a simple interface for scheduling background tasks. Useful for UnitTesting ASP.net code
        /// 
        public interface ITaskScheduler
        {
            /// 
            /// Schedules a task which can run in the background, independent of any request.
            /// 
            /// A unit of execution.
            [SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
            void QueueBackgroundWorkItem(Action workItem);
    
            /// 
            /// Schedules a task which can run in the background, independent of any request.
            /// 
            /// A unit of execution.
            [SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
            void QueueBackgroundWorkItem(Func workItem);
        }
    
    
        public class BackgroundTaskScheduler : BackgroundService, ITaskScheduler
        {
            public BackgroundTaskScheduler(ILogger logger)
            {
                _logger = logger;
            }
    
            protected override async Task ExecuteAsync(CancellationToken stoppingToken)
            {
                _logger.LogTrace("BackgroundTaskScheduler Service started.");
    
                _stoppingToken = stoppingToken;
    
                _isRunning = true;
                try
                {
                    await Task.Delay(-1, stoppingToken);
                }
                catch (TaskCanceledException)
                {
                }
                finally
                {
                    _isRunning = false;
                    _logger.LogTrace("BackgroundTaskScheduler Service stopped.");
                }
            }
    
            public void QueueBackgroundWorkItem(Action workItem)
            {
                if (workItem == null)
                {
                    throw new ArgumentNullException(nameof(workItem));
                }
    
                if (!_isRunning)
                    throw new Exception("BackgroundTaskScheduler is not running.");
    
                _ = Task.Run(() => workItem(_stoppingToken), _stoppingToken);
            }
    
            public void QueueBackgroundWorkItem(Func workItem)
            {
                if (workItem == null)
                {
                    throw new ArgumentNullException(nameof(workItem));
                }
    
                if (!_isRunning)
                    throw new Exception("BackgroundTaskScheduler is not running.");
    
                _ = Task.Run(async () =>
                    {
                        try
                        {
                            await workItem(_stoppingToken);
                        }
                        catch (Exception e)
                        {
                            _logger.LogError(e, "When executing background task.");
                            throw;
                        }
                    }, _stoppingToken);
            }
    
            private readonly ILogger _logger;
            private volatile bool _isRunning;
            private CancellationToken _stoppingToken;
        }
    

    The ITaskScheduler (which we already defined in our old ASP.NET client code for UTest test purposes) allows a client to add a background task. The main purpose of the BackgroundTaskScheduler is to capture the stop cancellation token (which is own by the Host) and to pass it into all the background Tasks; which by definition, runs in the System.Threading.ThreadPool so there is no need to create our own.

    To configure Hosted Services properly see this post.

    Enjoy!

提交回复
热议问题