Merge remote-tracking branch 'origin/release/15.0' into v15/dev

# Conflicts:
#	src/Umbraco.Core/Services/DocumentUrlService.cs
#	src/Umbraco.Web.UI.Client
#	tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/ContentNavigationServiceBaseTests.cs
This commit is contained in:
Jacob Overgaard
2024-10-17 09:02:19 +02:00
79 changed files with 2264 additions and 323 deletions

View File

@@ -1,18 +1,37 @@
using Umbraco.Cms.Core.PublishedCache;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Logging;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.HybridCache.Persistence;
namespace Umbraco.Cms.Infrastructure.HybridCache;
internal class DatabaseCacheRebuilder : IDatabaseCacheRebuilder
{
private const string NuCacheSerializerKey = "Umbraco.Web.PublishedCache.NuCache.Serializer";
private readonly IDatabaseCacheRepository _databaseCacheRepository;
private readonly ICoreScopeProvider _coreScopeProvider;
private readonly IOptions<NuCacheSettings> _nucacheSettings;
private readonly IKeyValueService _keyValueService;
private readonly ILogger<DatabaseCacheRebuilder> _logger;
private readonly IProfilingLogger _profilingLogger;
public DatabaseCacheRebuilder(IDatabaseCacheRepository databaseCacheRepository, ICoreScopeProvider coreScopeProvider)
public DatabaseCacheRebuilder(
IDatabaseCacheRepository databaseCacheRepository,
ICoreScopeProvider coreScopeProvider,
IOptions<NuCacheSettings> nucacheSettings,
IKeyValueService keyValueService,
ILogger<DatabaseCacheRebuilder> logger, IProfilingLogger profilingLogger)
{
_databaseCacheRepository = databaseCacheRepository;
_coreScopeProvider = coreScopeProvider;
_nucacheSettings = nucacheSettings;
_keyValueService = keyValueService;
_logger = logger;
_profilingLogger = profilingLogger;
}
public void Rebuild()
@@ -21,4 +40,28 @@ internal class DatabaseCacheRebuilder : IDatabaseCacheRebuilder
_databaseCacheRepository.Rebuild();
scope.Complete();
}
public void RebuildDatabaseCacheIfSerializerChanged()
{
using var scope = _coreScopeProvider.CreateCoreScope();
NuCacheSerializerType serializer = _nucacheSettings.Value.NuCacheSerializerType;
var currentSerializerValue = _keyValueService.GetValue(NuCacheSerializerKey);
if (Enum.TryParse(currentSerializerValue, out NuCacheSerializerType currentSerializer) && serializer == currentSerializer)
{
return;
}
_logger.LogWarning(
"Database cache was serialized using {CurrentSerializer}. Currently configured cache serializer {Serializer}. Rebuilding database cache.",
currentSerializer, serializer);
using (_profilingLogger.TraceDuration<DatabaseCacheRebuilder>($"Rebuilding database cache with {serializer} serializer"))
{
Rebuild();
_keyValueService.SetValue(NuCacheSerializerKey, serializer.ToString());
}
scope.Complete();
}
}

View File

@@ -60,6 +60,7 @@ public static class UmbracoBuilderExtensions
throw new IndexOutOfRangeException();
}
});
builder.AddNotificationAsyncHandler<UmbracoApplicationStartingNotification, HybridCacheStartupNotificationHandler>(); // Need to happen before notification handlers use the cache. Eg. seeding
builder.Services.AddSingleton<IPropertyCacheCompressionOptions, NoopPropertyCacheCompressionOptions>();
builder.AddNotificationAsyncHandler<ContentRefreshNotification, CacheRefreshingNotificationHandler>();
builder.AddNotificationAsyncHandler<ContentDeletedNotification, CacheRefreshingNotificationHandler>();

View File

@@ -0,0 +1,32 @@
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Infrastructure.HybridCache.NotificationHandlers;
/// <summary>
/// Rebuilds the database cache if required when the serializer changes
/// </summary>
public class HybridCacheStartupNotificationHandler : INotificationAsyncHandler<UmbracoApplicationStartingNotification>
{
private readonly IDatabaseCacheRebuilder _databaseCacheRebuilder;
private readonly IRuntimeState _runtimeState;
public HybridCacheStartupNotificationHandler(IDatabaseCacheRebuilder databaseCacheRebuilder, IRuntimeState runtimeState)
{
_databaseCacheRebuilder = databaseCacheRebuilder;
_runtimeState = runtimeState;
}
public Task HandleAsync(UmbracoApplicationStartingNotification notification, CancellationToken cancellationToken)
{
if (_runtimeState.Level > RuntimeLevel.Install)
{
_databaseCacheRebuilder.RebuildDatabaseCacheIfSerializerChanged();
}
return Task.CompletedTask;
}
}

View File

@@ -1,4 +1,6 @@
using Umbraco.Cms.Core;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Services;
@@ -11,19 +13,21 @@ internal class SeedingNotificationHandler : INotificationAsyncHandler<UmbracoApp
private readonly IDocumentCacheService _documentCacheService;
private readonly IMediaCacheService _mediaCacheService;
private readonly IRuntimeState _runtimeState;
private readonly GlobalSettings _globalSettings;
public SeedingNotificationHandler(IDocumentCacheService documentCacheService, IMediaCacheService mediaCacheService, IRuntimeState runtimeState)
public SeedingNotificationHandler(IDocumentCacheService documentCacheService, IMediaCacheService mediaCacheService, IRuntimeState runtimeState, IOptions<GlobalSettings> globalSettings)
{
_documentCacheService = documentCacheService;
_mediaCacheService = mediaCacheService;
_runtimeState = runtimeState;
_globalSettings = globalSettings.Value;
}
public async Task HandleAsync(UmbracoApplicationStartedNotification notification,
CancellationToken cancellationToken)
{
if (_runtimeState.Level <= RuntimeLevel.Install)
if (_runtimeState.Level <= RuntimeLevel.Install || (_runtimeState.Level == RuntimeLevel.Upgrade && _globalSettings.ShowMaintenancePageWhenInUpgradeState))
{
return;
}

View File

@@ -886,7 +886,7 @@ WHERE cmsContentNu.nodeId IN (
dto.VersionId,
dto.PubVersionDate,
dto.CreatorId,
dto.EditTemplateId == 0 ? null : dto.EditTemplateId,
dto.PubTemplateId == 0 ? null : dto.PubTemplateId,
true,
deserializedContent?.PropertyData,
deserializedContent?.CultureData);