Caching: Resolves publish and install issues related to stale cached data retrieval (closes #20539 and #20630) (#20640)
* Request cache published content creation with version. * Reload memory cache after install with package migrations. * Improve message on install for database cache rebuild. * Update src/Umbraco.Infrastructure/Install/MigrationPlansExecutedNotificationHandler.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Relocated memory cache refresh after package install from notification handler to unattended upgrader. * Fix construtor breaking change --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
This commit is contained in:
@@ -20,6 +20,7 @@ public static partial class UmbracoBuilderExtensions
|
|||||||
|
|
||||||
// Add post migration notification handlers
|
// Add post migration notification handlers
|
||||||
builder.AddNotificationHandler<UmbracoPlanExecutedNotification, ClearCsrfCookieHandler>();
|
builder.AddNotificationHandler<UmbracoPlanExecutedNotification, ClearCsrfCookieHandler>();
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Umbraco.Cms.Core;
|
using Umbraco.Cms.Core;
|
||||||
|
using Umbraco.Cms.Core.Cache;
|
||||||
using Umbraco.Cms.Core.Configuration;
|
using Umbraco.Cms.Core.Configuration;
|
||||||
using Umbraco.Cms.Core.Configuration.Models;
|
using Umbraco.Cms.Core.Configuration.Models;
|
||||||
using Umbraco.Cms.Core.DependencyInjection;
|
using Umbraco.Cms.Core.DependencyInjection;
|
||||||
@@ -28,7 +30,10 @@ public class UnattendedUpgrader : INotificationAsyncHandler<RuntimeUnattendedUpg
|
|||||||
private readonly IRuntimeState _runtimeState;
|
private readonly IRuntimeState _runtimeState;
|
||||||
private readonly IUmbracoVersion _umbracoVersion;
|
private readonly IUmbracoVersion _umbracoVersion;
|
||||||
private readonly UnattendedSettings _unattendedSettings;
|
private readonly UnattendedSettings _unattendedSettings;
|
||||||
|
private readonly DistributedCache _distributedCache;
|
||||||
|
private readonly ILogger<UnattendedUpgrader> _logger;
|
||||||
|
|
||||||
|
[Obsolete("Please use the constructor taking all parameters. Scheduled for removal in Umbraco 19.")]
|
||||||
public UnattendedUpgrader(
|
public UnattendedUpgrader(
|
||||||
IProfilingLogger profilingLogger,
|
IProfilingLogger profilingLogger,
|
||||||
IUmbracoVersion umbracoVersion,
|
IUmbracoVersion umbracoVersion,
|
||||||
@@ -36,13 +41,36 @@ public class UnattendedUpgrader : INotificationAsyncHandler<RuntimeUnattendedUpg
|
|||||||
IRuntimeState runtimeState,
|
IRuntimeState runtimeState,
|
||||||
PackageMigrationRunner packageMigrationRunner,
|
PackageMigrationRunner packageMigrationRunner,
|
||||||
IOptions<UnattendedSettings> unattendedSettings)
|
IOptions<UnattendedSettings> unattendedSettings)
|
||||||
|
: this(
|
||||||
|
profilingLogger,
|
||||||
|
umbracoVersion,
|
||||||
|
databaseBuilder,
|
||||||
|
runtimeState,
|
||||||
|
packageMigrationRunner,
|
||||||
|
unattendedSettings,
|
||||||
|
StaticServiceProvider.Instance.GetRequiredService<DistributedCache>(),
|
||||||
|
StaticServiceProvider.Instance.GetRequiredService<ILogger<UnattendedUpgrader>>())
|
||||||
{
|
{
|
||||||
_profilingLogger = profilingLogger ?? throw new ArgumentNullException(nameof(profilingLogger));
|
}
|
||||||
_umbracoVersion = umbracoVersion ?? throw new ArgumentNullException(nameof(umbracoVersion));
|
|
||||||
_databaseBuilder = databaseBuilder ?? throw new ArgumentNullException(nameof(databaseBuilder));
|
public UnattendedUpgrader(
|
||||||
_runtimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState));
|
IProfilingLogger profilingLogger,
|
||||||
|
IUmbracoVersion umbracoVersion,
|
||||||
|
DatabaseBuilder databaseBuilder,
|
||||||
|
IRuntimeState runtimeState,
|
||||||
|
PackageMigrationRunner packageMigrationRunner,
|
||||||
|
IOptions<UnattendedSettings> unattendedSettings,
|
||||||
|
DistributedCache distributedCache,
|
||||||
|
ILogger<UnattendedUpgrader> logger)
|
||||||
|
{
|
||||||
|
_profilingLogger = profilingLogger;
|
||||||
|
_umbracoVersion = umbracoVersion;
|
||||||
|
_databaseBuilder = databaseBuilder;
|
||||||
|
_runtimeState = runtimeState;
|
||||||
_packageMigrationRunner = packageMigrationRunner;
|
_packageMigrationRunner = packageMigrationRunner;
|
||||||
_unattendedSettings = unattendedSettings.Value;
|
_unattendedSettings = unattendedSettings.Value;
|
||||||
|
_distributedCache = distributedCache;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task HandleAsync(RuntimeUnattendedUpgradeNotification notification, CancellationToken cancellationToken)
|
public async Task HandleAsync(RuntimeUnattendedUpgradeNotification notification, CancellationToken cancellationToken)
|
||||||
@@ -109,8 +137,13 @@ public class UnattendedUpgrader : INotificationAsyncHandler<RuntimeUnattendedUpg
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _packageMigrationRunner.RunPackagePlansAsync(pendingMigrations);
|
await _packageMigrationRunner.RunPackagePlansAsync(pendingMigrations);
|
||||||
notification.UnattendedUpgradeResult = RuntimeUnattendedUpgradeNotification.UpgradeResult
|
notification.UnattendedUpgradeResult = RuntimeUnattendedUpgradeNotification.UpgradeResult.PackageMigrationComplete;
|
||||||
.PackageMigrationComplete;
|
|
||||||
|
// Migration plans may have changed published content, so refresh the distributed cache to ensure consistency on first request.
|
||||||
|
_distributedCache.RefreshAllPublishedSnapshot();
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Migration plans run: {Plans}. Triggered refresh of distributed published content cache.",
|
||||||
|
string.Join(", ", pendingMigrations));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ internal sealed class DatabaseCacheRebuilder : IDatabaseCacheRebuilder
|
|||||||
|
|
||||||
_logger.LogWarning(
|
_logger.LogWarning(
|
||||||
"Database cache was serialized using {CurrentSerializer}. Currently configured cache serializer {Serializer}. Rebuilding database cache.",
|
"Database cache was serialized using {CurrentSerializer}. Currently configured cache serializer {Serializer}. Rebuilding database cache.",
|
||||||
currentSerializer,
|
currentSerializer == 0 ? "None" : currentSerializer,
|
||||||
serializer);
|
serializer);
|
||||||
|
|
||||||
using (_profilingLogger.TraceDuration<DatabaseCacheRebuilder>($"Rebuilding database cache with {serializer} serializer"))
|
using (_profilingLogger.TraceDuration<DatabaseCacheRebuilder>($"Rebuilding database cache with {serializer} serializer"))
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ internal sealed class PublishedContentFactory : IPublishedContentFactory
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IPublishedContent? ToIPublishedContent(ContentCacheNode contentCacheNode, bool preview)
|
public IPublishedContent? ToIPublishedContent(ContentCacheNode contentCacheNode, bool preview)
|
||||||
{
|
{
|
||||||
var cacheKey = $"{nameof(PublishedContentFactory)}DocumentCache_{contentCacheNode.Id}_{preview}";
|
var cacheKey = $"{nameof(PublishedContentFactory)}DocumentCache_{contentCacheNode.Id}_{preview}_{contentCacheNode.Data?.VersionDate.Ticks ?? 0}";
|
||||||
IPublishedContent? publishedContent = null;
|
IPublishedContent? publishedContent = null;
|
||||||
if (_appCaches.RequestCache.IsAvailable)
|
if (_appCaches.RequestCache.IsAvailable)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user