diff --git a/src/Umbraco.Core/Sync/DatabaseServerRegistrarOptions.cs b/src/Umbraco.Core/Sync/DatabaseServerRegistrarOptions.cs
index 33ab1c8f57..5b5f6fc457 100644
--- a/src/Umbraco.Core/Sync/DatabaseServerRegistrarOptions.cs
+++ b/src/Umbraco.Core/Sync/DatabaseServerRegistrarOptions.cs
@@ -1,4 +1,5 @@
using System;
+using System.ComponentModel;
namespace Umbraco.Core.Sync
{
@@ -14,13 +15,18 @@ namespace Umbraco.Core.Sync
{
StaleServerTimeout = TimeSpan.FromMinutes(2); // 2 minutes
ThrottleSeconds = 30; // 30 seconds
+ RecurringSeconds = 60; // do it every minute
}
- ///
- /// The number of seconds to wait between each updates to the database.
- ///
+ [Obsolete("This is no longer used")]
+ [EditorBrowsable(EditorBrowsableState.Never)]
public int ThrottleSeconds { get; set; }
+ ///
+ /// The amount of seconds to wait between calls to the database on the background thread
+ ///
+ public int RecurringSeconds { get; set; }
+
///
/// The time span to wait before considering a server stale, after it has last been accessed.
///
diff --git a/src/Umbraco.Web/Strategies/ServerRegistrationEventHandler.cs b/src/Umbraco.Web/Strategies/ServerRegistrationEventHandler.cs
index 2a61d4177d..9106d43960 100644
--- a/src/Umbraco.Web/Strategies/ServerRegistrationEventHandler.cs
+++ b/src/Umbraco.Web/Strategies/ServerRegistrationEventHandler.cs
@@ -1,4 +1,6 @@
using System;
+using System.Threading;
+using System.Threading.Tasks;
using System.Web;
using Newtonsoft.Json;
using Umbraco.Core;
@@ -6,6 +8,7 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Services;
using Umbraco.Core.Sync;
using Umbraco.Web.Routing;
+using Umbraco.Web.Scheduling;
namespace Umbraco.Web.Strategies
{
@@ -22,74 +25,137 @@ namespace Umbraco.Web.Strategies
///
public sealed class ServerRegistrationEventHandler : ApplicationEventHandler
{
- private readonly object _locko = new object();
private DatabaseServerRegistrar _registrar;
- private DateTime _lastUpdated = DateTime.MinValue;
+ private BackgroundTaskRunner _backgroundTaskRunner;
+ private bool _started = false;
// bind to events
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
_registrar = ServerRegistrarResolver.Current.Registrar as DatabaseServerRegistrar;
+ _backgroundTaskRunner = new BackgroundTaskRunner(
+ new BackgroundTaskRunnerOptions { AutoStart = true },
+ applicationContext.ProfilingLogger.Logger);
+
// only for the DatabaseServerRegistrar
if (_registrar == null) return;
+ //We will start the whole process when a successful request is made
UmbracoModule.RouteAttempt += UmbracoModuleRouteAttempt;
}
- // handles route attempts.
+ ///
+ /// Handle when a request is made
+ ///
+ ///
+ ///
+ ///
+ /// We require this because:
+ /// - ApplicationContext.UmbracoApplicationUrl is initialized by UmbracoModule in BeginRequest
+ /// - RegisterServer is called on UmbracoModule.RouteAttempt which is triggered in ProcessRequest
+ /// we are safe, UmbracoApplicationUrl has been initialized
+ ///
private void UmbracoModuleRouteAttempt(object sender, RoutableAttemptEventArgs e)
{
- if (e.HttpContext.Request == null || e.HttpContext.Request.Url == null) return;
-
switch (e.Outcome)
{
case EnsureRoutableOutcome.IsRoutable:
// front-end request
RegisterServer(e);
+ //remove handler, we're done
+ UmbracoModule.RouteAttempt -= UmbracoModuleRouteAttempt;
break;
case EnsureRoutableOutcome.NotDocumentRequest:
// anything else (back-end request, service...)
//so it's not a document request, we'll check if it's a back office request
if (e.HttpContext.Request.Url.IsBackOfficeRequest(HttpRuntime.AppDomainAppVirtualPath))
+ {
RegisterServer(e);
- break;
- /*
- case EnsureRoutableOutcome.NotReady:
- case EnsureRoutableOutcome.NotConfigured:
- case EnsureRoutableOutcome.NoContent:
- default:
- // otherwise, do nothing
- break;
- */
+ //remove handler, we're done
+ UmbracoModule.RouteAttempt -= UmbracoModuleRouteAttempt;
+ }
+ break;
}
}
-
- // register current server (throttled).
+
private void RegisterServer(UmbracoRequestEventArgs e)
{
- lock (_locko) // ensure we trigger only once
- {
- var secondsSinceLastUpdate = DateTime.Now.Subtract(_lastUpdated).TotalSeconds;
- if (secondsSinceLastUpdate < _registrar.Options.ThrottleSeconds) return;
- _lastUpdated = DateTime.Now;
- }
+ //only process once
+ if (_started) return;
+ _started = true;
+
+ var serverAddress = e.UmbracoContext.Application.UmbracoApplicationUrl;
var svc = e.UmbracoContext.Application.Services.ServerRegistrationService;
- // because
- // - ApplicationContext.UmbracoApplicationUrl is initialized by UmbracoModule in BeginRequest
- // - RegisterServer is called on UmbracoModule.RouteAttempt which is triggered in ProcessRequest
- // we are safe, UmbracoApplicationUrl has been initialized
- var serverAddress = e.UmbracoContext.Application.UmbracoApplicationUrl;
+ //Perform the rest async, we don't want to block the startup sequence
+ // this will just reoccur on a background thread
+ _backgroundTaskRunner.Add(new TouchServerTask(_backgroundTaskRunner,
+ 5, //delay before first execution
+ _registrar.Options.RecurringSeconds * 1000, //amount of ms between executions
+ svc, _registrar, serverAddress));
+ }
- try
+ private class TouchServerTask : RecurringTaskBase
+ {
+ private readonly IServerRegistrationService _svc;
+ private readonly DatabaseServerRegistrar _registrar;
+ private readonly string _serverAddress;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The task runner.
+ /// The delay.
+ /// The period.
+ ///
+ ///
+ ///
+ /// The task will repeat itself periodically. Use this constructor to create a new task.
+ public TouchServerTask(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds,
+ IServerRegistrationService svc, DatabaseServerRegistrar registrar, string serverAddress)
+ : base(runner, delayMilliseconds, periodMilliseconds)
{
- svc.TouchServer(serverAddress, svc.CurrentServerIdentity, _registrar.Options.StaleServerTimeout);
+ if (svc == null) throw new ArgumentNullException("svc");
+ _svc = svc;
+ _registrar = registrar;
+ _serverAddress = serverAddress;
}
- catch (Exception ex)
+
+ public override bool IsAsync
{
- LogHelper.Error("Failed to update server record in database.", ex);
+ get { return false; }
+ }
+
+ public override bool RunsOnShutdown
+ {
+ get { return false; }
+ }
+
+ ///
+ /// Runs the background task.
+ ///
+ /// A value indicating whether to repeat the task.
+ public override bool PerformRun()
+ {
+ try
+ {
+ _svc.TouchServer(_serverAddress, _svc.CurrentServerIdentity, _registrar.Options.StaleServerTimeout);
+
+ return true; // repeat
+ }
+ catch (Exception ex)
+ {
+ LogHelper.Error("Failed to update server record in database.", ex);
+
+ return false; // probably stop if we have an error
+ }
+ }
+
+ public override Task PerformRunAsync(CancellationToken token)
+ {
+ throw new NotImplementedException();
}
}
}