From 596c745a19b604e444e505a09e4c913c7b6eb61f Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 10 Sep 2019 13:35:59 +1000 Subject: [PATCH] Uses an event on UmbracoContext for when the snapshot is created so we can block until the background notifier is completed --- .../BackgroundPublishedSnapshotNotifier.cs | 4 -- src/Umbraco.Web/UmbracoContext.cs | 11 +++- src/Umbraco.Web/UmbracoInjectedModule.cs | 55 ++++++------------- 3 files changed, 28 insertions(+), 42 deletions(-) diff --git a/src/Umbraco.Web/Cache/BackgroundPublishedSnapshotNotifier.cs b/src/Umbraco.Web/Cache/BackgroundPublishedSnapshotNotifier.cs index f1da2b6375..5efbf988a4 100644 --- a/src/Umbraco.Web/Cache/BackgroundPublishedSnapshotNotifier.cs +++ b/src/Umbraco.Web/Cache/BackgroundPublishedSnapshotNotifier.cs @@ -109,10 +109,6 @@ namespace Umbraco.Web.Cache _publishedSnapshotService.Notify(_dataTypePayloads); if (_contentTypePayloads != null) _publishedSnapshotService.Notify(_contentTypePayloads); - - //Thread.Sleep(10000); - - var asdf = ""; }); } diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index c0306e0a81..e4a921375e 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -59,7 +59,11 @@ namespace Umbraco.Web Security = webSecurity; // beware - we cannot expect a current user here, so detecting preview mode must be a lazy thing - _publishedSnapshot = new Lazy(() => publishedSnapshotService.CreatePublishedSnapshot(PreviewToken)); + _publishedSnapshot = new Lazy(() => + { + CreatingPublishedSnapshot?.Invoke(this, new EventArgs()); + return publishedSnapshotService.CreatePublishedSnapshot(PreviewToken); + }); // set the urls... // NOTE: The request will not be available during app startup so we can only set this to an absolute URL of localhost, this @@ -73,6 +77,11 @@ namespace Umbraco.Web UrlProvider = new UrlProvider(this, umbracoSettings.WebRouting, urlProviders, mediaUrlProviders, variationContextAccessor); } + /// + /// Raised when the published snapshot is being created + /// + internal event EventHandler CreatingPublishedSnapshot; + /// /// This is used internally for performance calculations, the ObjectCreated DateTime is set as soon as this /// object is instantiated which in the web site is created during the BeginRequest phase. diff --git a/src/Umbraco.Web/UmbracoInjectedModule.cs b/src/Umbraco.Web/UmbracoInjectedModule.cs index 99d167fbd3..cbeee34444 100644 --- a/src/Umbraco.Web/UmbracoInjectedModule.cs +++ b/src/Umbraco.Web/UmbracoInjectedModule.cs @@ -2,7 +2,6 @@ using System.Collections; using System.Collections.Generic; using System.IO; -using System.Text; using System.Web; using System.Web.Routing; using Umbraco.Core; @@ -10,16 +9,10 @@ using Umbraco.Core.Configuration; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Web.Routing; -using Umbraco.Web.Security; using Umbraco.Core.Exceptions; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Persistence.FaultHandling; using Umbraco.Core.Security; -using Umbraco.Core.Services; using Umbraco.Web.Composing; -using Umbraco.Web.PublishedCache; using Umbraco.Web.Cache; -using Umbraco.Web.PublishedCache.NuCache; namespace Umbraco.Web { @@ -41,41 +34,26 @@ namespace Umbraco.Web public class UmbracoInjectedModule : IHttpModule { private readonly IGlobalSettings _globalSettings; - private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly IPublishedSnapshotService _publishedSnapshotService; - private readonly IUserService _userService; - private readonly UrlProviderCollection _urlProviders; private readonly IRuntimeState _runtime; private readonly ILogger _logger; private readonly IPublishedRouter _publishedRouter; - private readonly IVariationContextAccessor _variationContextAccessor; private readonly IUmbracoContextFactory _umbracoContextFactory; private readonly BackgroundPublishedSnapshotNotifier _backgroundNotifier; public UmbracoInjectedModule( IGlobalSettings globalSettings, - IUmbracoContextAccessor umbracoContextAccessor, - IPublishedSnapshotService publishedSnapshotService, - IUserService userService, - UrlProviderCollection urlProviders, IRuntimeState runtime, ILogger logger, IPublishedRouter publishedRouter, - IVariationContextAccessor variationContextAccessor, IUmbracoContextFactory umbracoContextFactory, BackgroundPublishedSnapshotNotifier backgroundNotifier) { _combinedRouteCollection = new Lazy(CreateRouteCollection); _globalSettings = globalSettings; - _umbracoContextAccessor = umbracoContextAccessor; - _publishedSnapshotService = publishedSnapshotService; - _userService = userService; - _urlProviders = urlProviders; _runtime = runtime; _logger = logger; _publishedRouter = publishedRouter; - _variationContextAccessor = variationContextAccessor; _umbracoContextFactory = umbracoContextFactory; _backgroundNotifier = backgroundNotifier; } @@ -104,9 +82,27 @@ namespace Umbraco.Web // ensure there's an UmbracoContext registered for the current request // registers the context reference so its disposed at end of request var umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext(httpContext); + umbracoContextReference.UmbracoContext.CreatingPublishedSnapshot += UmbracoContext_CreatingPublishedSnapshot; httpContext.DisposeOnPipelineCompleted(umbracoContextReference); } + /// + /// Event handler for when the UmbracoContext creates the published snapshot + /// + /// + /// + private void UmbracoContext_CreatingPublishedSnapshot(object sender, EventArgs e) + { + // Wait for the notifier to complete if it's in progress, this is required because + // Pure Live models along with content snapshots are updated on a background thread when schema + // (doc types, data types) are changed so if that is still processing we need to wait before we access + // the content snapshot to make sure it's the latest version. + if (_backgroundNotifier.Wait()) + { + _logger.Debug("Request was suspended while waiting for background cache notifications to complete"); + } + } + /// /// Processes the Umbraco Request /// @@ -141,21 +137,6 @@ namespace Umbraco.Web // do not process if this request is not a front-end routable page var isRoutableAttempt = EnsureUmbracoRoutablePage(umbracoContext, httpContext); - // If this page is probably front-end routable, block here until the backround notifier isn't busy - if (isRoutableAttempt) - { - //wait for the notifier to complete if it's in progress - if (_backgroundNotifier.Wait()) - { - // if we were waiting, we need to resync the snapshot - // TODO: This does not belong here! BUT we cannot Resync the snapshot on the background process because there is no snapshot... - // normally it would do that automatically but on a background thread it is null ... hrm.... - ((PublishedSnapshot)_publishedSnapshotService.PublishedSnapshotAccessor.PublishedSnapshot)?.Resync(); - var done = "done"; - } - } - - // raise event here UmbracoModule.OnRouteAttempt(this, new RoutableAttemptEventArgs(isRoutableAttempt.Result, umbracoContext, httpContext)); if (isRoutableAttempt.Success == false) return;