2014-06-20 14:34:21 +10:00
using System.Threading ;
using Umbraco.Core ;
2014-06-25 11:00:11 +10:00
using Umbraco.Core.Logging ;
2014-06-20 14:34:21 +10:00
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/
///
2014-06-20 14:34:21 +10:00
/// </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 ;
2014-06-20 14:34:21 +10:00
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-20 14:34:21 +10:00
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-20 14:34:21 +10:00
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-20 14:34:21 +10:00
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
2014-06-20 14:34:21 +10:00
//log scrubbing
_scrubber = new LogScrubber ( ) ;
_scrubber . Start ( ) ;
2014-06-25 11:00:11 +10:00
}
2014-06-20 14:34:21 +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-20 14:34:21 +10:00
{
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-20 14:34:21 +10:00
2014-06-25 11:00:11 +10:00
//do the scheduled publishing
var scheduledPublishing = new ScheduledPublishing ( ) ;
2014-06-25 11:56:36 +10:00
scheduledPublishing . Start ( ApplicationContext . Current ) ;
2014-06-25 11:00:11 +10:00
//do the scheduled tasks
var scheduledTasks = new ScheduledTasks ( ) ;
2014-06-25 11:56:36 +10:00
scheduledTasks . Start ( ApplicationContext . Current ) ;
2014-06-20 14:34:21 +10:00
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-20 14:34:21 +10:00
2014-06-25 11:00:11 +10:00
break ;
}
2014-06-20 14:34:21 +10:00
}
}
2014-06-25 11:00:11 +10:00
}
2014-06-20 14:34:21 +10:00
}