2021-03-03 13:43:27 +11:00
|
|
|
// Copyright (c) Umbraco.
|
|
|
|
|
// See LICENSE for more details.
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
|
2022-06-21 08:09:38 +02:00
|
|
|
namespace Umbraco.Cms.Tests.Common;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Helper class to not repeat common patterns with Task.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed class TaskHelper
|
2021-03-03 13:43:27 +11:00
|
|
|
{
|
2022-06-21 08:09:38 +02:00
|
|
|
private readonly ILogger<TaskHelper> _logger;
|
|
|
|
|
|
|
|
|
|
public TaskHelper(ILogger<TaskHelper> logger) => _logger = logger;
|
|
|
|
|
|
2021-03-03 13:43:27 +11:00
|
|
|
/// <summary>
|
2022-06-21 08:09:38 +02:00
|
|
|
/// Executes a fire and forget task outside of the current execution flow.
|
2021-03-03 13:43:27 +11:00
|
|
|
/// </summary>
|
2022-06-21 08:09:38 +02:00
|
|
|
public void RunBackgroundTask(Func<Task> fn) => ExecuteBackgroundTask(fn);
|
2021-03-03 13:43:27 +11:00
|
|
|
|
2022-06-21 08:09:38 +02:00
|
|
|
// for tests, returning the Task as a public API indicates it can be awaited that is not what we want to do
|
|
|
|
|
public Task ExecuteBackgroundTask(Func<Task> fn)
|
|
|
|
|
{
|
|
|
|
|
// it is also possible to use UnsafeQueueUserWorkItem which does not flow the execution context,
|
|
|
|
|
// however that seems more difficult to use for async operations.
|
2021-03-03 13:43:27 +11:00
|
|
|
|
2022-06-21 08:09:38 +02:00
|
|
|
// Do not flow AsyncLocal to the child thread
|
|
|
|
|
using (ExecutionContext.SuppressFlow())
|
2021-03-03 13:43:27 +11:00
|
|
|
{
|
2022-06-21 08:09:38 +02:00
|
|
|
// NOTE: ConfigureAwait(false) is irrelevant here, it is not needed because this is not being
|
|
|
|
|
// awaited. ConfigureAwait(false) is only relevant when awaiting to prevent the SynchronizationContext
|
|
|
|
|
// (very different from the ExecutionContext!) from running the continuation on the calling thread.
|
|
|
|
|
return Task.Run(LoggingWrapper(fn));
|
2021-03-03 13:43:27 +11:00
|
|
|
}
|
2022-06-21 08:09:38 +02:00
|
|
|
}
|
2021-03-03 13:43:27 +11:00
|
|
|
|
2022-06-21 08:09:38 +02:00
|
|
|
/// <summary>
|
|
|
|
|
/// Executes a fire and forget task outside of the current execution flow on a dedicated (non thread-pool) thread.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void RunLongRunningBackgroundTask(Func<Task> fn) => ExecuteLongRunningBackgroundTask(fn);
|
|
|
|
|
|
|
|
|
|
// for tests, returning the Task as a public API indicates it can be awaited that is not what we want to do
|
|
|
|
|
public Task ExecuteLongRunningBackgroundTask(Func<Task> fn)
|
|
|
|
|
{
|
|
|
|
|
// it is also possible to use UnsafeQueueUserWorkItem which does not flow the execution context,
|
|
|
|
|
// however that seems more difficult to use for async operations.
|
2021-03-03 13:43:27 +11:00
|
|
|
|
2022-06-21 08:09:38 +02:00
|
|
|
// Do not flow AsyncLocal to the child thread
|
|
|
|
|
using (ExecutionContext.SuppressFlow())
|
2021-03-03 13:43:27 +11:00
|
|
|
{
|
2022-06-21 08:09:38 +02:00
|
|
|
// NOTE: ConfigureAwait(false) is irrelevant here, it is not needed because this is not being
|
|
|
|
|
// awaited. ConfigureAwait(false) is only relevant when awaiting to prevent the SynchronizationContext
|
|
|
|
|
// (very different from the ExecutionContext!) from running the continuation on the calling thread.
|
|
|
|
|
return Task.Factory.StartNew(LoggingWrapper(fn), TaskCreationOptions.LongRunning);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-03 13:43:27 +11:00
|
|
|
|
2022-06-21 08:09:38 +02:00
|
|
|
// ensure any exceptions are handled and do not take down the app pool
|
|
|
|
|
private Func<Task> LoggingWrapper(Func<Task> fn) =>
|
|
|
|
|
async () =>
|
|
|
|
|
{
|
|
|
|
|
try
|
2021-03-03 13:43:27 +11:00
|
|
|
{
|
2022-06-21 08:09:38 +02:00
|
|
|
await fn();
|
2021-03-03 13:43:27 +11:00
|
|
|
}
|
2022-06-21 08:09:38 +02:00
|
|
|
catch (Exception e)
|
2021-03-03 13:43:27 +11:00
|
|
|
{
|
2022-06-21 08:09:38 +02:00
|
|
|
_logger.LogError(e, "Exception thrown in a background thread");
|
|
|
|
|
}
|
|
|
|
|
};
|
2021-03-03 13:43:27 +11:00
|
|
|
}
|