Skip to content

Commit e8a9c4d

Browse files
Merge branch 'v8/dev' into v8/contrib
2 parents d08b84d + 2f60a47 commit e8a9c4d

File tree

28 files changed

+952
-296
lines changed

28 files changed

+952
-296
lines changed

src/SolutionInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@
1818
[assembly: AssemblyVersion("8.0.0")]
1919

2020
// these are FYI and changed automatically
21-
[assembly: AssemblyFileVersion("8.12.1")]
22-
[assembly: AssemblyInformationalVersion("8.12.1")]
21+
[assembly: AssemblyFileVersion("8.12.2")]
22+
[assembly: AssemblyInformationalVersion("8.12.2")]

src/Umbraco.Core/ConfigsExtensions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
using System.IO;
22
using Umbraco.Core.Cache;
3-
using Umbraco.Core.Composing;
43
using Umbraco.Core.Configuration;
54
using Umbraco.Core.Configuration.Grid;
65
using Umbraco.Core.Configuration.HealthChecks;
76
using Umbraco.Core.Configuration.UmbracoSettings;
7+
using Umbraco.Core.Dashboards;
88
using Umbraco.Core.IO;
99
using Umbraco.Core.Logging;
1010
using Umbraco.Core.Manifest;
@@ -48,6 +48,8 @@ public static void AddCoreConfigs(this Configs configs)
4848
configDir,
4949
factory.GetInstance<ManifestParser>(),
5050
factory.GetInstance<IRuntimeState>().Debug));
51+
52+
configs.Add<IContentDashboardSettings>(() => new ContentDashboardSettings());
5153
}
5254
}
5355
}

src/Umbraco.Core/Configuration/GlobalSettings.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,6 @@ public bool UseHttps
395395
}
396396
}
397397

398-
399398
/// <summary>
400399
/// An int value representing the time in milliseconds to lock the database for a write operation
401400
/// </summary>

src/Umbraco.Core/Constants-AppSettings.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ public static class AppSettings
110110
/// </summary>
111111
public const string UseHttps = "Umbraco.Core.UseHttps";
112112

113+
/// <summary>
114+
/// A true/false value indicating whether the content dashboard should be visible for all user groups.
115+
/// </summary>
116+
public const string AllowContentDashboardAccessToAllUsers = "Umbraco.Core.AllowContentDashboardAccessToAllUsers";
117+
113118
/// <summary>
114119
/// TODO: FILL ME IN
115120
/// </summary>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.Configuration;
2+
3+
namespace Umbraco.Core.Dashboards
4+
{
5+
public class ContentDashboardSettings: IContentDashboardSettings
6+
{
7+
8+
/// <summary>
9+
/// Gets a value indicating whether the content dashboard should be available to all users.
10+
/// </summary>
11+
/// <value>
12+
/// <c>true</c> if the dashboard is visible for all user groups; otherwise, <c>false</c>
13+
/// and the default access rules for that dashboard will be in use.
14+
/// </value>
15+
public bool AllowContentDashboardAccessToAllUsers
16+
{
17+
get
18+
{
19+
bool.TryParse(ConfigurationManager.AppSettings[Constants.AppSettings.AllowContentDashboardAccessToAllUsers], out var value);
20+
return value;
21+
}
22+
}
23+
}
24+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace Umbraco.Core.Dashboards
2+
{
3+
public interface IContentDashboardSettings
4+
{
5+
/// <summary>
6+
/// Gets a value indicating whether the content dashboard should be available to all users.
7+
/// </summary>
8+
/// <value>
9+
/// <c>true</c> if the dashboard is visible for all user groups; otherwise, <c>false</c>
10+
/// and the default access rules for that dashboard will be in use.
11+
/// </value>
12+
bool AllowContentDashboardAccessToAllUsers { get; }
13+
}
14+
}

src/Umbraco.Core/Runtime/MainDom.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,14 @@ private bool Acquire()
179179
_listenTask = _mainDomLock.ListenAsync();
180180
_listenCompleteTask = _listenTask.ContinueWith(t =>
181181
{
182-
_logger.Debug<MainDom>("Listening task completed with {TaskStatus}", _listenTask.Status);
182+
if (_listenTask.Exception != null)
183+
{
184+
_logger.Warn<MainDom>("Listening task completed with {TaskStatus}, Exception: {Exception}", _listenTask.Status, _listenTask.Exception);
185+
}
186+
else
187+
{
188+
_logger.Debug<MainDom>("Listening task completed with {TaskStatus}", _listenTask.Status);
189+
}
183190

184191
OnSignal("signal");
185192
}, TaskScheduler.Default); // Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html

src/Umbraco.Core/Runtime/SqlMainDomLock.cs

Lines changed: 58 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public async Task<bool> AcquireLockAsync(int millisecondsTimeout)
8686
// wait to get a write lock
8787
_sqlServerSyntax.WriteLock(db, TimeSpan.FromMilliseconds(millisecondsTimeout), Constants.Locks.MainDom);
8888
}
89-
catch(SqlException ex)
89+
catch (SqlException ex)
9090
{
9191
if (IsLockTimeoutException(ex))
9292
{
@@ -126,7 +126,7 @@ public async Task<bool> AcquireLockAsync(int millisecondsTimeout)
126126
}
127127

128128

129-
return await WaitForExistingAsync(tempId, millisecondsTimeout);
129+
return await WaitForExistingAsync(tempId, millisecondsTimeout).ConfigureAwait(false);
130130
}
131131

132132
public Task ListenAsync()
@@ -139,13 +139,15 @@ public Task ListenAsync()
139139

140140
// Create a long running task (dedicated thread)
141141
// to poll to check if we are still the MainDom registered in the DB
142-
return Task.Factory.StartNew(
143-
ListeningLoop,
144-
_cancellationTokenSource.Token,
145-
TaskCreationOptions.LongRunning,
146-
// Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html
147-
TaskScheduler.Default);
148-
142+
using (ExecutionContext.SuppressFlow())
143+
{
144+
return Task.Factory.StartNew(
145+
ListeningLoop,
146+
_cancellationTokenSource.Token,
147+
TaskCreationOptions.LongRunning,
148+
// Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html
149+
TaskScheduler.Default);
150+
}
149151
}
150152

151153
/// <summary>
@@ -227,11 +229,29 @@ private void ListeningLoop()
227229
}
228230
finally
229231
{
230-
db?.CompleteTransaction();
231-
db?.Dispose();
232+
// Even if any of the above fail like BeginTransaction, or even a query after the
233+
// Transaction is started, the calls below will not throw. I've tried all sorts of
234+
// combinations to see if I can make this throw but I can't. In any case, we'll be
235+
// extra safe and try/catch/log
236+
try
237+
{
238+
db?.CompleteTransaction();
239+
}
240+
catch (Exception ex)
241+
{
242+
_logger.Error<SqlMainDomLock>(ex, "Unexpected error completing transaction.");
243+
}
244+
245+
try
246+
{
247+
db?.Dispose();
248+
}
249+
catch (Exception ex)
250+
{
251+
_logger.Error<SqlMainDomLock>(ex, "Unexpected error completing disposing.");
252+
}
232253
}
233254
}
234-
235255
}
236256
}
237257

@@ -245,37 +265,40 @@ private Task<bool> WaitForExistingAsync(string tempId, int millisecondsTimeout)
245265
{
246266
var updatedTempId = tempId + UpdatedSuffix;
247267

248-
return Task.Run(() =>
268+
using (ExecutionContext.SuppressFlow())
249269
{
250-
try
270+
return Task.Run(() =>
251271
{
252-
using var db = _dbFactory.CreateDatabase();
253-
254-
var watch = new Stopwatch();
255-
watch.Start();
256-
while (true)
272+
try
257273
{
258-
// poll very often, we need to take over as fast as we can
259-
// local testing shows the actual query to be executed from client/server is approx 300ms but would change depending on environment/IO
260-
Thread.Sleep(1000);
261-
262-
var acquired = TryAcquire(db, tempId, updatedTempId);
263-
if (acquired.HasValue)
264-
return acquired.Value;
274+
using var db = _dbFactory.CreateDatabase();
265275

266-
if (watch.ElapsedMilliseconds >= millisecondsTimeout)
276+
var watch = new Stopwatch();
277+
watch.Start();
278+
while (true)
267279
{
268-
return AcquireWhenMaxWaitTimeElapsed(db);
280+
// poll very often, we need to take over as fast as we can
281+
// local testing shows the actual query to be executed from client/server is approx 300ms but would change depending on environment/IO
282+
Thread.Sleep(1000);
283+
284+
var acquired = TryAcquire(db, tempId, updatedTempId);
285+
if (acquired.HasValue)
286+
return acquired.Value;
287+
288+
if (watch.ElapsedMilliseconds >= millisecondsTimeout)
289+
{
290+
return AcquireWhenMaxWaitTimeElapsed(db);
291+
}
269292
}
270293
}
271-
}
272-
catch (Exception ex)
273-
{
274-
_logger.Error<SqlMainDomLock>(ex, "An error occurred trying to acquire and waiting for existing SqlMainDomLock to shutdown");
275-
return false;
276-
}
294+
catch (Exception ex)
295+
{
296+
_logger.Error<SqlMainDomLock>(ex, "An error occurred trying to acquire and waiting for existing SqlMainDomLock to shutdown");
297+
return false;
298+
}
277299

278-
}, _cancellationTokenSource.Token);
300+
}, _cancellationTokenSource.Token);
301+
}
279302
}
280303

281304
private bool? TryAcquire(IUmbracoDatabase db, string tempId, string updatedTempId)

0 commit comments

Comments
 (0)