Merge branch 'v8/8.8' into v8/8.9

This commit is contained in:
Sebastiaan Janssen
2020-12-15 14:25:17 +01:00
8 changed files with 79 additions and 11 deletions

View File

@@ -1,4 +1,5 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Umbraco.Core.Logging
@@ -14,7 +15,12 @@ namespace Umbraco.Core.Logging
/// </summary>
public static Task LogErrors(this Task task, Action<string, Exception> logMethod)
{
return task.ContinueWith(t => LogErrorsInner(t, logMethod), TaskContinuationOptions.OnlyOnFaulted);
return task.ContinueWith(
t => LogErrorsInner(t, logMethod),
CancellationToken.None,
TaskContinuationOptions.OnlyOnFaulted,
// Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html
TaskScheduler.Default);
}
/// <summary>
@@ -26,7 +32,10 @@ namespace Umbraco.Core.Logging
/// </summary>
public static Task LogErrorsWaitable(this Task task, Action<string, Exception> logMethod)
{
return task.ContinueWith(t => LogErrorsInner(t, logMethod));
return task.ContinueWith(
t => LogErrorsInner(t, logMethod),
// Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html
TaskScheduler.Default);
}
private static void LogErrorsInner(Task task, Action<string, Exception> logAction)

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Hosting;
using Umbraco.Core;
using Umbraco.Core.Logging;
@@ -38,6 +39,9 @@ namespace Umbraco.Core.Runtime
private const int LockTimeoutMilliseconds = 40000; // 40 seconds
private Task _listenTask;
private Task _listenCompleteTask;
#endregion
#region Ctor
@@ -172,7 +176,13 @@ namespace Umbraco.Core.Runtime
try
{
// Listen for the signal from another AppDomain coming online to release the lock
_mainDomLock.ListenAsync().ContinueWith(_ => OnSignal("signal"));
_listenTask = _mainDomLock.ListenAsync();
_listenCompleteTask = _listenTask.ContinueWith(t =>
{
_logger.Debug<MainDom>("Listening task completed with {TaskStatus}", _listenTask.Status);
OnSignal("signal");
}, TaskScheduler.Default); // Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html
}
catch (OperationCanceledException ex)
{

View File

@@ -125,7 +125,12 @@ namespace Umbraco.Core.Runtime
// Create a long running task (dedicated thread)
// to poll to check if we are still the MainDom registered in the DB
return Task.Factory.StartNew(ListeningLoop, _cancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
return Task.Factory.StartNew(
ListeningLoop,
_cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
// Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html
TaskScheduler.Default);
}
@@ -166,7 +171,11 @@ namespace Umbraco.Core.Runtime
// the other MainDom is taking to startup. In this case the db row will just be deleted and the
// new MainDom will just take over.
if (_cancellationTokenSource.IsCancellationRequested)
{
_logger.Debug<SqlMainDomLock>("Task canceled, exiting loop");
return;
}
IUmbracoDatabase db = null;
try
{
@@ -190,8 +199,10 @@ namespace Umbraco.Core.Runtime
// We need to keep on listening unless we've been notified by our own AppDomain to shutdown since
// we don't want to shutdown resources controlled by MainDom inadvertently. We'll just keep listening otherwise.
if (_cancellationTokenSource.IsCancellationRequested)
{
_logger.Debug<SqlMainDomLock>("Task canceled, exiting loop");
return;
}
}
finally
{
@@ -396,6 +407,8 @@ namespace Umbraco.Core.Runtime
{
lock (_locker)
{
_logger.Debug<SqlMainDomLock>($"{nameof(SqlMainDomLock)} Disposing...");
// immediately cancel all sub-tasks, we don't want them to keep querying
_cancellationTokenSource.Cancel();
_cancellationTokenSource.Dispose();

View File

@@ -1380,7 +1380,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
_collectTask = null;
}
}, TaskContinuationOptions.ExecuteSynchronously);
},
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
// Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html
TaskScheduler.Default);
// ReSharper restore InconsistentlySynchronizedField
return task;

View File

@@ -380,7 +380,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
_collectTask = null;
}
}, TaskContinuationOptions.ExecuteSynchronously);
},
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
// Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html
TaskScheduler.Default);
// ReSharper restore InconsistentlySynchronizedField
return task;

View File

@@ -756,9 +756,17 @@ namespace Umbraco.Web.Scheduling
lock (_locker)
{
if (_runningTask != null)
_runningTask.ContinueWith(_ => StopImmediate());
{
_runningTask.ContinueWith(
_ => StopImmediate(),
// Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html
TaskScheduler.Default);
}
else
{
StopImmediate();
}
}
}

View File

@@ -8,6 +8,7 @@ namespace Umbraco.Web.Scheduling
{
#region Task Extensions
// TODO: Not used, is this used in Deploy or something?
static void SetCompletionSource<TResult>(TaskCompletionSource<TResult> completionSource, Task task)
{
if (task.IsFaulted)
@@ -16,6 +17,7 @@ namespace Umbraco.Web.Scheduling
completionSource.SetResult(default(TResult));
}
// TODO: Not used, is this used in Deploy or something?
static void SetCompletionSource<TResult>(TaskCompletionSource<TResult> completionSource, Task<TResult> task)
{
if (task.IsFaulted)
@@ -24,17 +26,33 @@ namespace Umbraco.Web.Scheduling
completionSource.SetResult(task.Result);
}
// TODO: Not used, is this used in Deploy or something?
public static Task ContinueWithTask(this Task task, Func<Task, Task> continuation)
{
var completionSource = new TaskCompletionSource<object>();
task.ContinueWith(atask => continuation(atask).ContinueWith(atask2 => SetCompletionSource(completionSource, atask2)));
task.ContinueWith(atask => continuation(atask).ContinueWith(
atask2 => SetCompletionSource(completionSource, atask2),
// Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html
TaskScheduler.Default),
// Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html
TaskScheduler.Default);
return completionSource.Task;
}
// TODO: Not used, is this used in Deploy or something?
public static Task ContinueWithTask(this Task task, Func<Task, Task> continuation, CancellationToken token)
{
var completionSource = new TaskCompletionSource<object>();
task.ContinueWith(atask => continuation(atask).ContinueWith(atask2 => SetCompletionSource(completionSource, atask2), token), token);
task.ContinueWith(atask => continuation(atask).ContinueWith(
atask2 => SetCompletionSource(completionSource, atask2),
token,
TaskContinuationOptions.None,
// Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html
TaskScheduler.Default),
token,
TaskContinuationOptions.None,
// Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html
TaskScheduler.Default);
return completionSource.Task;
}

View File

@@ -89,7 +89,9 @@ namespace Umbraco.Web.WebApi
throw x.Exception;
}
result = x.ConfigureAwait(false).GetAwaiter().GetResult();
});
},
// Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html
TaskScheduler.Default);
task.Wait();
if (result == null)