diff --git a/src/Umbraco.Infrastructure/HostedServices/RecurringHostedServiceBase.cs b/src/Umbraco.Infrastructure/HostedServices/RecurringHostedServiceBase.cs index 70dcb3a04e..b6f2b469f6 100644 --- a/src/Umbraco.Infrastructure/HostedServices/RecurringHostedServiceBase.cs +++ b/src/Umbraco.Infrastructure/HostedServices/RecurringHostedServiceBase.cs @@ -21,7 +21,7 @@ namespace Umbraco.Cms.Infrastructure.HostedServices /// protected static readonly TimeSpan DefaultDelay = TimeSpan.FromMinutes(3); - private readonly TimeSpan _period; + private TimeSpan _period; private readonly TimeSpan _delay; private Timer _timer; @@ -73,6 +73,7 @@ namespace Umbraco.Cms.Infrastructure.HostedServices /// public Task StopAsync(CancellationToken cancellationToken) { + _period = Timeout.InfiniteTimeSpan; _timer?.Change(Timeout.Infinite, 0); return Task.CompletedTask; } diff --git a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs b/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs index 282847963f..d54d67338e 100644 --- a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs +++ b/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs @@ -2,13 +2,17 @@ // See LICENSE for more details. using System; +using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Sync; +using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.HostedServices.ServerRegistration @@ -22,6 +26,7 @@ namespace Umbraco.Cms.Infrastructure.HostedServices.ServerRegistration private readonly IServerRegistrationService _serverRegistrationService; private readonly IHostingEnvironment _hostingEnvironment; private readonly ILogger _logger; + private readonly IServerRoleAccessor _serverRoleAccessor; private readonly GlobalSettings _globalSettings; /// @@ -37,7 +42,8 @@ namespace Umbraco.Cms.Infrastructure.HostedServices.ServerRegistration IServerRegistrationService serverRegistrationService, IHostingEnvironment hostingEnvironment, ILogger logger, - IOptions globalSettings) + IOptions globalSettings, + IServerRoleAccessor serverRoleAccessor) : base(globalSettings.Value.DatabaseServerRegistrar.WaitTimeBetweenCalls, TimeSpan.FromSeconds(15)) { _runtimeState = runtimeState; @@ -45,6 +51,24 @@ namespace Umbraco.Cms.Infrastructure.HostedServices.ServerRegistration _hostingEnvironment = hostingEnvironment; _logger = logger; _globalSettings = globalSettings.Value; + _serverRoleAccessor = serverRoleAccessor; + } + + [Obsolete("Use constructor that takes an IServerRoleAccessor")] + public TouchServerTask( + IRuntimeState runtimeState, + IServerRegistrationService serverRegistrationService, + IHostingEnvironment hostingEnvironment, + ILogger logger, + IOptions globalSettings) + : this( + runtimeState, + serverRegistrationService, + hostingEnvironment, + logger, + globalSettings, + StaticServiceProvider.Instance.GetRequiredService()) + { } public override Task PerformExecuteAsync(object state) @@ -54,6 +78,14 @@ namespace Umbraco.Cms.Infrastructure.HostedServices.ServerRegistration return Task.CompletedTask; } + // If the IServerRoleAccessor has been changed away from ElectedServerRoleAccessor this task no longer makes sense, + // since all it's used for is to allow the ElectedServerRoleAccessor + // to figure out what role a given server has, so we just stop this task. + if (_serverRoleAccessor is not ElectedServerRoleAccessor) + { + return StopAsync(CancellationToken.None); + } + var serverAddress = _hostingEnvironment.ApplicationMainUrl?.ToString(); if (serverAddress.IsNullOrWhiteSpace()) { diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTaskTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTaskTests.cs index 29b011a5a6..c690f35b7a 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTaskTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTaskTests.cs @@ -11,6 +11,7 @@ using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Sync; using Umbraco.Cms.Infrastructure.HostedServices.ServerRegistration; namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices.ServerRegistration @@ -51,7 +52,15 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices.Serv VerifyServerTouched(); } - private TouchServerTask CreateTouchServerTask(RuntimeLevel runtimeLevel = RuntimeLevel.Run, string applicationUrl = ApplicationUrl) + [Test] + public async Task Does_Not_Execute_When_Role_Accessor_Is_Not_Elected() + { + TouchServerTask sut = CreateTouchServerTask(useElection: false); + await sut.PerformExecuteAsync(null); + VerifyServerNotTouched(); + } + + private TouchServerTask CreateTouchServerTask(RuntimeLevel runtimeLevel = RuntimeLevel.Run, string applicationUrl = ApplicationUrl, bool useElection = true) { var mockRequestAccessor = new Mock(); mockRequestAccessor.SetupGet(x => x.ApplicationMainUrl).Returns(!string.IsNullOrEmpty(applicationUrl) ? new Uri(ApplicationUrl) : null); @@ -71,12 +80,17 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices.Serv } }; + IServerRoleAccessor roleAccessor = useElection + ? new ElectedServerRoleAccessor(_mockServerRegistrationService.Object) + : new SingleServerRoleAccessor(); + return new TouchServerTask( mockRunTimeState.Object, _mockServerRegistrationService.Object, mockRequestAccessor.Object, mockLogger.Object, - Options.Create(settings)); + Options.Create(settings), + roleAccessor); } private void VerifyServerNotTouched() => VerifyServerTouchedTimes(Times.Never());