diff --git a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs index e446e049b63e..00a33c0b6c52 100644 --- a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs +++ b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs @@ -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; @@ -148,7 +149,6 @@ public void CanHandleEvent() { // works because that event definition maps to an empty handler new EventDefinition>(null, Current.Services.ContentTypeService, new SaveEventArgs(Enumerable.Empty()), "Saved"), - }; var umbracoContextFactory = new UmbracoContextFactory( @@ -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.EventArgs>(null, Current.Services.ContentTypeService, new ContentTypeChange.EventArgs(Enumerable.Empty>()), "Changed"), + new EventDefinition>(null, Current.Services.ContentTypeService, new SaveEventArgs(Enumerable.Empty()), "Saved"), + new EventDefinition.EventArgs>(null, Current.Services.ContentTypeService, new ContentTypeChange.EventArgs(Enumerable.Empty>()), "Changed"), + new EventDefinition>(null, Current.Services.ContentTypeService, new SaveEventArgs(Enumerable.Empty()), "Saved"), + }; + var result = DistributedCacheBinder.GetReducedEventList(definitions); + Assert.AreEqual(1, result.Count()); + } } } diff --git a/src/Umbraco.Web/Cache/DistributedCacheBinder.cs b/src/Umbraco.Web/Cache/DistributedCacheBinder.cs index 3ee24a23bfd1..e3a5a01d54d8 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheBinder.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheBinder.cs @@ -61,11 +61,15 @@ internal static MethodInfo FindHandler(IEventDefinition eventDefinition) /// public void HandleEvents(IEnumerable 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) @@ -80,5 +84,49 @@ public void HandleEvents(IEnumerable events) } } } + + // Internal for tests + internal static IEnumerable GetReducedEventList(IEnumerable events) + { + var reducedEvents = new List(); + + 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; + } } }