From 2a609e1ecac1fb89ae85707edb4abe00ee2cca10 Mon Sep 17 00:00:00 2001 From: Mole Date: Fri, 14 Nov 2025 14:14:28 +0100 Subject: [PATCH] Load Balancing: Clear request cache in cache version accessor on cache version update to prevent unnecessary cache roll forwards (#20831) * Clear request cache on version update * Update src/Umbraco.Core/Cache/IRepositoryCacheVersionAccessor.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Cache/IRepositoryCacheVersionAccessor.cs | 11 +++++++++-- .../Cache/RepositoryCacheVersionService.cs | 1 + .../Cache/RepositoryCacheVersionAccessor.cs | 12 ++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Cache/IRepositoryCacheVersionAccessor.cs b/src/Umbraco.Core/Cache/IRepositoryCacheVersionAccessor.cs index 61ae733fe1..af304dc19e 100644 --- a/src/Umbraco.Core/Cache/IRepositoryCacheVersionAccessor.cs +++ b/src/Umbraco.Core/Cache/IRepositoryCacheVersionAccessor.cs @@ -20,7 +20,14 @@ public interface IRepositoryCacheVersionAccessor /// /// The cache version if found, or if the version doesn't exist or the request is a client-side request. /// - public Task GetAsync(string cacheKey); + Task GetAsync(string cacheKey); + + /// + /// Notifies of a version change on a given cache key. + /// + /// Key of the changed version. + void VersionChanged(string cacheKey) + { } /// /// Notifies the accessor that caches have been synchronized. @@ -29,5 +36,5 @@ public interface IRepositoryCacheVersionAccessor /// This method is called after cache synchronization to temporarily bypass version checking, /// preventing recursive sync attempts while repositories reload data from the database. /// - public void CachesSynced(); + void CachesSynced(); } diff --git a/src/Umbraco.Core/Cache/RepositoryCacheVersionService.cs b/src/Umbraco.Core/Cache/RepositoryCacheVersionService.cs index 541e9f032e..09269f92e1 100644 --- a/src/Umbraco.Core/Cache/RepositoryCacheVersionService.cs +++ b/src/Umbraco.Core/Cache/RepositoryCacheVersionService.cs @@ -88,6 +88,7 @@ internal class RepositoryCacheVersionService : IRepositoryCacheVersionService _logger.LogDebug("Setting cache for {EntityType} to version {Version}", typeof(TEntity).Name, newVersion); await _repositoryCacheVersionRepository.SaveAsync(new RepositoryCacheVersion { Identifier = cacheKey, Version = newVersion.ToString() }); _cacheVersions[cacheKey] = newVersion; + _repositoryCacheVersionAccessor.VersionChanged(cacheKey); scope.Complete(); } diff --git a/src/Umbraco.Web.Common/Cache/RepositoryCacheVersionAccessor.cs b/src/Umbraco.Web.Common/Cache/RepositoryCacheVersionAccessor.cs index b96e2546e1..4485c80834 100644 --- a/src/Umbraco.Web.Common/Cache/RepositoryCacheVersionAccessor.cs +++ b/src/Umbraco.Web.Common/Cache/RepositoryCacheVersionAccessor.cs @@ -77,5 +77,17 @@ public class RepositoryCacheVersionAccessor : IRepositoryCacheVersionAccessor return databaseVersion; } + + /// + public void VersionChanged(string cacheKey) + { + var removed = _requestCache.Remove(cacheKey); + if (removed is false) + { + _logger.LogDebug("Cache version for key {CacheKey} wasn't removed from request cache, possibly missing HTTP context", cacheKey); + } + } + + /// public void CachesSynced() => _requestCache.ClearOfType(); }