Alternative solution to HostingEnvironment.QueueBackgroundWorkItem in .NET Core

后端 未结 6 1873
栀梦
栀梦 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:22

    Here is a tweaked version of Axel's answer that lets you pass in delegates and does more aggressive cleanup of completed tasks.

    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Logging;
    
    namespace Example
    {
        public class BackgroundPool
        {
            private readonly ILogger _logger;
            private readonly IApplicationLifetime _lifetime;
            private readonly object _currentTasksLock = new object();
            private readonly List _currentTasks = new List();
    
            public BackgroundPool(ILogger logger, IApplicationLifetime lifetime)
            {
                if (logger == null)
                    throw new ArgumentNullException(nameof(logger));
                if (lifetime == null)
                    throw new ArgumentNullException(nameof(lifetime));
    
                _logger = logger;
                _lifetime = lifetime;
    
                _lifetime.ApplicationStopped.Register(() =>
                {
                    lock (_currentTasksLock)
                    {
                        Task.WaitAll(_currentTasks.ToArray());
                    }
    
                    _logger.LogInformation("Background pool closed.");
                });
            }
    
            public void QueueBackgroundWork(Action action)
            {
    #pragma warning disable 1998
                async Task Wrapper() => action();
    #pragma warning restore 1998
    
                QueueBackgroundWork(Wrapper);
            }
    
            public void QueueBackgroundWork(Func func)
            {
                var task = Task.Run(async () =>
                {
                    _logger.LogTrace("Queuing background work.");
    
                    try
                    {
                        await func();
    
                        _logger.LogTrace("Background work returns.");
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex.HResult, ex, "Background work failed.");
                    }
                }, _lifetime.ApplicationStopped);
    
                lock (_currentTasksLock)
                {
                    _currentTasks.Add(task);
                }
    
                task.ContinueWith(CleanupOnComplete, _lifetime.ApplicationStopping);
            }
    
            private void CleanupOnComplete(Task oldTask)
            {
                lock (_currentTasksLock)
                {
                    _currentTasks.Remove(oldTask);
                }
            }
        }
    }
    

提交回复
热议问题