Permalink
Browse files

Properly resolve scoped services in the background task queue

  • Loading branch information...
Daniel15 committed Nov 9, 2017
1 parent d36ba29 commit 5614b23efc887b93bc3a0de446227a06bcfd9d9f
@@ -9,6 +9,7 @@
using Daniel15.Web.Extensions;
using Daniel15.Web.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
namespace Daniel15.Web.Controllers
{
@@ -90,8 +91,14 @@ public ActionResult Index(string uri)
var ip = HttpContext.Connection.RemoteIpAddress;
var userAgent = Request.Headers["User-Agent"].ToString();
var referrer = Request.Headers["Referer"].ToString();
_taskQueue.QueueBackgroundWorkItem(
async token => await _shortUrlLogger.LogHitAsync(shortenedUrl.Id, ip, userAgent, referrer, token)
_taskQueue.QueueBackgroundWorkItem(async (provider, token) =>
await provider.GetRequiredService<IShortUrlLogger>().LogHitAsync(
shortenedUrl.Id,
ip,
userAgent,
referrer,
token
)
);
// TODO: redirect
@@ -8,10 +8,10 @@ namespace Daniel15.Web.Services
// https://github.com/aspnet/Docs/issues/3352#issuecomment-333593326
public class BackgroundTaskQueue : IBackgroundTaskQueue
{
private readonly ConcurrentQueue<Func<CancellationToken, Task>> _workItems = new ConcurrentQueue<Func<CancellationToken, Task>>();
private readonly ConcurrentQueue<Func<IServiceProvider, CancellationToken, Task>> _workItems = new ConcurrentQueue<Func<IServiceProvider, CancellationToken, Task>>();
private readonly SemaphoreSlim _signal = new SemaphoreSlim(0);
public void QueueBackgroundWorkItem(Func<CancellationToken, Task> workItem)
public void QueueBackgroundWorkItem(Func<IServiceProvider, CancellationToken, Task> workItem)
{
if (workItem == null)
{
@@ -22,7 +22,7 @@ public void QueueBackgroundWorkItem(Func<CancellationToken, Task> workItem)
_signal.Release();
}
public async Task<Func<CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken)
public async Task<Func<IServiceProvider, CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken)
{
await _signal.WaitAsync(cancellationToken);
_workItems.TryDequeue(out var workItem);
@@ -1,6 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
@@ -10,12 +11,14 @@ namespace Daniel15.Web.Services
public class BackgroundTaskService : IHostedService
{
private readonly ILogger<BackgroundTaskService> _logger;
private readonly IServiceProvider _serviceProvider;
private readonly CancellationTokenSource _shutdown = new CancellationTokenSource();
private Task _backgroundTask;
public BackgroundTaskService(IBackgroundTaskQueue taskQueue, ILogger<BackgroundTaskService> logger)
public BackgroundTaskService(IBackgroundTaskQueue taskQueue, ILogger<BackgroundTaskService> logger, IServiceProvider serviceProvider)
{
_logger = logger;
_serviceProvider = serviceProvider;
TaskQueue = taskQueue ?? throw new ArgumentNullException(nameof(taskQueue));
}
@@ -29,19 +32,22 @@ public Task StartAsync(CancellationToken cancellationToken)
private async Task BackgroundProcessing()
{
while (!_shutdown.IsCancellationRequested)
using (var scope = _serviceProvider.CreateScope())
{
var workItem = await TaskQueue.DequeueAsync(_shutdown.Token);
try
{
_logger.LogInformation("Starting background task");
await workItem(_shutdown.Token);
_logger.LogInformation("Completed background task");
}
catch (Exception ex)
while (!_shutdown.IsCancellationRequested)
{
_logger.LogError(ex, "Error while running background job");
var workItem = await TaskQueue.DequeueAsync(_shutdown.Token);
try
{
_logger.LogInformation("Starting background task");
await workItem(scope.ServiceProvider, _shutdown.Token);
_logger.LogInformation("Completed background task");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while running background job");
}
}
}
}
@@ -15,8 +15,8 @@ public interface IBackgroundTaskQueue
/// will be signaled when the application is shutting down.
/// </summary>
/// <param name="workItem"></param>
void QueueBackgroundWorkItem(Func<CancellationToken, Task> workItem);
void QueueBackgroundWorkItem(Func<IServiceProvider, CancellationToken, Task> workItem);
Task<Func<CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken);
Task<Func<IServiceProvider, CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken);
}
}

0 comments on commit 5614b23

Please sign in to comment.