Files
Umbraco-CMS/src/Umbraco.Web/Scheduling/Scheduler.cs

102 lines
4.3 KiB
C#
Raw Normal View History

using System.Threading;
using Umbraco.Core;
2014-06-25 11:00:11 +10:00
using Umbraco.Core.Logging;
using Umbraco.Core.Sync;
namespace Umbraco.Web.Scheduling
{
/// <summary>
/// Used to do the scheduling for tasks, publishing, etc...
/// </summary>
/// <remarks>
///
/// TODO: Much of this code is legacy and needs to be updated, there are a few new/better ways to do scheduling
/// in a web project nowadays.
///
2014-06-25 11:36:14 +10:00
/// //TODO: We need a much more robust way of handing scheduled tasks and also need to take into account app shutdowns during
/// a scheduled tasks operation
/// http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx/
///
/// </remarks>
2014-06-25 11:00:11 +10:00
internal sealed class Scheduler : ApplicationEventHandler
{
2014-06-25 11:52:48 +10:00
private static Timer _pingTimer;
private static Timer _schedulingTimer;
private static LogScrubber _scrubber;
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
if (umbracoApplication.Context == null)
return;
2014-06-25 11:36:58 +10:00
LogHelper.Debug<Scheduler>(() => "Initializing the scheduler");
2014-06-25 11:00:11 +10:00
// time to setup the tasks
2014-06-25 11:00:11 +10:00
// these are the legacy tasks
// just copied over here for backward compatibility
// of course we should have a proper scheduler, see #U4-809
2014-06-25 11:52:48 +10:00
//NOTE: It is important to note that we need to use the ctor for a timer without the 'state' object specified, this is in order
// to ensure that the timer itself is not GC'd since internally .net will pass itself in as the state object and that will keep it alive.
// There's references to this here: http://stackoverflow.com/questions/4962172/why-does-a-system-timers-timer-survive-gc-but-not-system-threading-timer
// we also make these timers static to ensure further GC safety.
2014-06-25 11:52:48 +10:00
// ping/keepalive
_pingTimer = new Timer(KeepAlive.Start);
_pingTimer.Change(60000, 300000);
2014-06-25 11:00:11 +10:00
2014-06-25 11:52:48 +10:00
// scheduled publishing/unpublishing
_schedulingTimer = new Timer(PerformScheduling);
_schedulingTimer.Change(30000, 60000);
2014-06-25 11:00:11 +10:00
//log scrubbing
_scrubber = new LogScrubber();
_scrubber.Start();
2014-06-25 11:00:11 +10:00
}
/// <summary>
/// This performs all of the scheduling on the one timer
/// </summary>
/// <param name="sender"></param>
/// <remarks>
/// No processing will be done if this server is a slave
/// </remarks>
private static void PerformScheduling(object sender)
{
2014-06-25 11:00:11 +10:00
using (DisposableTimer.DebugDuration<Scheduler>(() => "Scheduling interval executing", () => "Scheduling interval complete"))
{
2014-06-25 11:00:11 +10:00
//get the current server status to see if this server should execute the scheduled publishing
var serverStatus = ServerEnvironmentHelper.GetStatus();
switch (serverStatus)
{
case CurrentServerEnvironmentStatus.Single:
case CurrentServerEnvironmentStatus.Master:
case CurrentServerEnvironmentStatus.Unknown:
//if it's a single server install, a master or it cannot be determined
// then we will process the scheduling
2014-06-25 11:00:11 +10:00
//do the scheduled publishing
var scheduledPublishing = new ScheduledPublishing();
scheduledPublishing.Start(ApplicationContext.Current);
2014-06-25 11:00:11 +10:00
//do the scheduled tasks
var scheduledTasks = new ScheduledTasks();
scheduledTasks.Start(ApplicationContext.Current);
2014-06-25 11:00:11 +10:00
break;
case CurrentServerEnvironmentStatus.Slave:
//do not process
LogHelper.Debug<Scheduler>(
() => string.Format("Current server ({0}) detected as a slave, no scheduled processes will execute on this server", NetworkHelper.MachineName));
2014-06-25 11:00:11 +10:00
break;
}
}
}
2014-06-25 11:00:11 +10:00
}
}