Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid repeated reloads of content and media cache following Deploy operations. #10360

Merged
merged 1 commit into from
Jun 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Changes;
using Umbraco.Tests.Testing;
using Umbraco.Tests.Testing.Objects.Accessors;
using Umbraco.Web;
Expand Down Expand Up @@ -148,7 +149,6 @@ public void CanHandleEvent()
{
// works because that event definition maps to an empty handler
new EventDefinition<IContentTypeService, SaveEventArgs<IContentType>>(null, Current.Services.ContentTypeService, new SaveEventArgs<IContentType>(Enumerable.Empty<IContentType>()), "Saved"),

};

var umbracoContextFactory = new UmbracoContextFactory(
Expand All @@ -166,5 +166,19 @@ public void CanHandleEvent()
var refreshers = new DistributedCacheBinder(null, umbracoContextFactory, null);
refreshers.HandleEvents(definitions);
}

[Test]
public void OnlyHandlesOnContentTypeEvent()
{
var definitions = new IEventDefinition[]
{
new EventDefinition<IContentTypeService, ContentTypeChange<IContentType>.EventArgs>(null, Current.Services.ContentTypeService, new ContentTypeChange<IContentType>.EventArgs(Enumerable.Empty<ContentTypeChange<IContentType>>()), "Changed"),
new EventDefinition<IContentTypeService, SaveEventArgs<IContentType>>(null, Current.Services.ContentTypeService, new SaveEventArgs<IContentType>(Enumerable.Empty<IContentType>()), "Saved"),
new EventDefinition<IContentTypeService, ContentTypeChange<IContentType>.EventArgs>(null, Current.Services.ContentTypeService, new ContentTypeChange<IContentType>.EventArgs(Enumerable.Empty<ContentTypeChange<IContentType>>()), "Changed"),
new EventDefinition<IContentTypeService, SaveEventArgs<IContentType>>(null, Current.Services.ContentTypeService, new SaveEventArgs<IContentType>(Enumerable.Empty<IContentType>()), "Saved"),
};
var result = DistributedCacheBinder.GetReducedEventList(definitions);
Assert.AreEqual(1, result.Count());
}
}
}
54 changes: 51 additions & 3 deletions src/Umbraco.Web/Cache/DistributedCacheBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,15 @@ internal static MethodInfo FindHandler(IEventDefinition eventDefinition)
/// <inheritdoc />
public void HandleEvents(IEnumerable<IEventDefinition> events)
{
// ensure we run with an UmbracoContext, because this may run in a background task,
// yet developers may be using the 'current' UmbracoContext in the event handlers
// Ensure we run with an UmbracoContext, because this may run in a background task,
// yet developers may be using the 'current' UmbracoContext in the event handlers.
using (_umbracoContextFactory.EnsureUmbracoContext())
{
foreach (var e in events)
// When it comes to content types types, a change to any single one will trigger a reload of the content and media caches.
// As far as I (AB) can tell, there's no type specific logic here, they all clear caches for all content types, and trigger a reload of all content and media.
// We also have events registered for Changed and Saved, which do the same thing, so really only need one of these.
// Hence if we have more than one document or media types, we can and should only handle one of the events for one, to avoid repeated cache reloads.
foreach (var e in GetReducedEventList(events))
{
var handler = FindHandler(e);
if (handler == null)
Expand All @@ -80,5 +84,49 @@ public void HandleEvents(IEnumerable<IEventDefinition> events)
}
}
}

// Internal for tests
internal static IEnumerable<IEventDefinition> GetReducedEventList(IEnumerable<IEventDefinition> events)
{
var reducedEvents = new List<IEventDefinition>();

var gotDoumentType = false;
var gotMediaType = false;
var gotMemberType = false;

foreach (var evt in events)
{
if (evt.Sender.ToString().Contains(nameof(Core.Services.Implement.ContentTypeService)))
{
if (gotDoumentType == false)
{
reducedEvents.Add(evt);
gotDoumentType = true;
}
}
else if (evt.Sender.ToString().Contains(nameof(Core.Services.Implement.MediaTypeService)))
{
if (gotMediaType == false)
{
reducedEvents.Add(evt);
gotMediaType = true;
}
}
else if (evt.Sender.ToString().Contains(nameof(Core.Services.Implement.MemberTypeService)))
{
if (gotMemberType == false)
{
reducedEvents.Add(evt);
gotMemberType = true;
}
}
else
{
reducedEvents.Add(evt);
}
}

return reducedEvents;
nul800sebastiaan marked this conversation as resolved.
Show resolved Hide resolved
}
}
}