Files
Umbraco-CMS/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs

133 lines
4.8 KiB
C#
Raw Normal View History

using System;
2019-06-24 11:58:36 +02:00
using System.Threading;
2020-07-13 13:38:41 +02:00
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.Logging;
using Umbraco.Core.Configuration;
using Umbraco.Configuration;
2020-07-13 13:38:41 +02:00
using Umbraco.Core;
2019-11-20 15:21:09 +01:00
using Umbraco.Core.Hosting;
using Umbraco.ModelsBuilder.Embedded.Building;
2019-06-24 11:58:36 +02:00
using Umbraco.Web.Cache;
using Umbraco.Core.Configuration.Models;
using Microsoft.Extensions.Options;
using Umbraco.Extensions;
2019-06-24 11:58:36 +02:00
namespace Umbraco.ModelsBuilder.Embedded
2019-06-24 11:58:36 +02:00
{
// supports LiveAppData - but not PureLive
2019-06-24 11:58:36 +02:00
public sealed class LiveModelsProvider
{
private static Mutex _mutex;
private static int _req;
private readonly ILogger<LiveModelsProvider> _logger;
private readonly ModelsBuilderSettings _config;
private readonly ModelsGenerator _modelGenerator;
private readonly ModelsGenerationError _mbErrors;
2019-11-20 15:21:09 +01:00
private readonly IHostingEnvironment _hostingEnvironment;
2019-06-24 11:58:36 +02:00
// we do not manage pure live here
internal bool IsEnabled => _config.ModelsMode.IsLiveNotPure();
Merge remote-tracking branch 'origin/netcore/netcore' into netcore/feature/migrate-logging Signed-off-by: Bjarke Berg <mail@bergmania.dk> # Conflicts: # src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs # src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs # src/Umbraco.Tests.Integration/Implementations/TestHelper.cs # src/Umbraco.Tests.Integration/Persistence/Repositories/TemplateRepositoryTest.cs # src/Umbraco.Tests.Integration/RuntimeTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ColorListValidatorTest.cs # src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/EnsureUniqueValuesValidatorTest.cs # src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs # src/Umbraco.Tests/Components/ComponentTests.cs # src/Umbraco.Tests/IO/ShadowFileSystemTests.cs # src/Umbraco.Tests/Models/VariationTests.cs # src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs # src/Umbraco.Tests/Persistence/DatabaseContextTests.cs # src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs # src/Umbraco.Tests/Persistence/Repositories/MediaTypeRepositoryTest.cs # src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs # src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs # src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs # src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs # src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs # src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs # src/Umbraco.Tests/Published/ConvertersTests.cs # src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs # src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs # src/Umbraco.Tests/Routing/ContentFinderByUrlAndTemplateTests.cs # src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs # src/Umbraco.Tests/Routing/UmbracoModuleTests.cs # src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs # src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs # src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs # src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs
2020-09-23 07:17:05 +02:00
public LiveModelsProvider(ILogger<LiveModelsProvider> logger, IOptions<ModelsBuilderSettings> config, ModelsGenerator modelGenerator, ModelsGenerationError mbErrors, IHostingEnvironment hostingEnvironment)
{
_logger = logger;
_config = config.Value ?? throw new ArgumentNullException(nameof(config));
_modelGenerator = modelGenerator;
_mbErrors = mbErrors;
2019-11-20 15:21:09 +01:00
_hostingEnvironment = hostingEnvironment;
}
2019-06-24 11:58:36 +02:00
internal void Install()
2019-06-24 11:58:36 +02:00
{
// just be sure
if (!IsEnabled)
return;
// initialize mutex
// ApplicationId will look like "/LM/W3SVC/1/Root/AppName"
// name is system-wide and must be less than 260 chars
2019-11-20 15:21:09 +01:00
var name = _hostingEnvironment.ApplicationId + "/UmbracoLiveModelsProvider";
_mutex = new Mutex(false, name); //TODO: Replace this with MainDom? Seems we now have 2x implementations of almost the same thing
2019-06-24 11:58:36 +02:00
// anything changes, and we want to re-generate models.
ContentTypeCacheRefresher.CacheUpdated += RequestModelsGeneration;
DataTypeCacheRefresher.CacheUpdated += RequestModelsGeneration;
// at the end of a request since we're restarting the pool
// NOTE - this does NOT trigger - see module below
//umbracoApplication.EndRequest += GenerateModelsIfRequested;
}
// NOTE
// Using HttpContext Items fails because CacheUpdated triggers within
// some asynchronous backend task where we seem to have no HttpContext.
// So we use a static (non request-bound) var to register that models
// need to be generated. Could be by another request. Anyway. We could
// have collisions but... you know the risk.
private void RequestModelsGeneration(object sender, EventArgs args)
2019-06-24 11:58:36 +02:00
{
//HttpContext.Current.Items[this] = true;
2020-09-16 10:24:05 +02:00
_logger.LogDebug("Requested to generate models.");
2019-06-24 11:58:36 +02:00
Interlocked.Exchange(ref _req, 1);
}
2020-07-13 13:38:41 +02:00
public void GenerateModelsIfRequested()
2019-06-24 11:58:36 +02:00
{
//if (HttpContext.Current.Items[this] == null) return;
if (Interlocked.Exchange(ref _req, 0) == 0) return;
// cannot use a simple lock here because we don't want another AppDomain
// to generate while we do... and there could be 2 AppDomains if the app restarts.
try
{
2020-09-16 10:24:05 +02:00
_logger.LogDebug("Generate models...");
const int timeout = 2 * 60 * 1000; // 2 mins
2019-06-24 11:58:36 +02:00
_mutex.WaitOne(timeout); // wait until it is safe, and acquire
2020-09-15 08:45:40 +02:00
_logger.LogInformation("Generate models now.");
2019-06-24 11:58:36 +02:00
GenerateModels();
_mbErrors.Clear();
2020-09-15 08:45:40 +02:00
_logger.LogInformation("Generated.");
2019-06-24 11:58:36 +02:00
}
catch (TimeoutException)
{
_logger.LogWarning("Timeout, models were NOT generated.");
2019-06-24 11:58:36 +02:00
}
catch (Exception e)
{
_mbErrors.Report("Failed to build Live models.", e);
_logger.LogError("Failed to generate models.", e);
2019-06-24 11:58:36 +02:00
}
finally
{
_mutex.ReleaseMutex(); // release
}
}
private void GenerateModels()
2019-06-24 11:58:36 +02:00
{
// EnableDllModels will recycle the app domain - but this request will end properly
_modelGenerator.GenerateModels();
2019-06-24 11:58:36 +02:00
}
2020-07-13 13:38:41 +02:00
public void AppEndRequest(HttpContext context)
{
if (context.Request.IsClientSideRequest())
{
return;
}
2020-07-13 13:38:41 +02:00
if (!IsEnabled)
{
2020-07-13 13:38:41 +02:00
return;
}
2020-07-13 13:38:41 +02:00
GenerateModelsIfRequested();
}
2019-06-24 11:58:36 +02:00
}
}