using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Newtonsoft.Json;
using umbraco.interfaces;
using Umbraco.Core;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Sync;
using Umbraco.Web.Routing;
using Umbraco.Core.Logging;
using Umbraco.Web.Scheduling;
namespace Umbraco.Web
{
///
/// An implementation that works by storing messages in the database.
///
///
/// This binds to appropriate umbraco events in order to trigger the Boot(), Sync() & FlushBatch() calls
///
public class BatchedDatabaseServerMessenger : DatabaseServerMessenger
{
public BatchedDatabaseServerMessenger(ApplicationContext appContext, bool enableDistCalls, DatabaseServerMessengerOptions options)
: base(appContext, enableDistCalls, options)
{
Scheduler.Initializing += Scheduler_Initializing;
}
///
/// Occurs when the scheduler initializes all scheduling activity when the app is ready
///
///
///
private void Scheduler_Initializing(object sender, List e)
{
//if the current resolver is 'this' then we will start the scheduling
var isMessenger = ServerMessengerResolver.HasCurrent && ReferenceEquals(ServerMessengerResolver.Current.Messenger, this);
if (isMessenger)
{
//start the background task runner for processing instructions
const int delayMilliseconds = 60000;
var instructionProcessingRunner = new BackgroundTaskRunner("InstructionProcessing", ApplicationContext.ProfilingLogger.Logger);
var instructionProcessingTask = new InstructionProcessing(instructionProcessingRunner, this, delayMilliseconds, Options.ThrottleSeconds * 1000);
instructionProcessingRunner.TryAdd(instructionProcessingTask);
e.Add(instructionProcessingTask);
}
}
// invoked by BatchedDatabaseServerMessengerStartup which is an ApplicationEventHandler
// with default "ShouldExecute", so that method will run if app IsConfigured and database
// context IsDatabaseConfigured - we still want to check CanConnect though to be safe
internal void Startup()
{
UmbracoModule.EndRequest += UmbracoModule_EndRequest;
if (ApplicationContext.DatabaseContext.CanConnect == false)
{
ApplicationContext.ProfilingLogger.Logger.Warn(
"Cannot connect to the database, distributed calls will not be enabled for this server.");
}
else
{
Boot();
}
}
///
/// This will process cache instructions on a background thread and will run every 5 seconds (or whatever is defined in the )
///
private class InstructionProcessing : RecurringTaskBase
{
private readonly DatabaseServerMessenger _messenger;
public InstructionProcessing(IBackgroundTaskRunner runner,
DatabaseServerMessenger messenger,
int delayMilliseconds, int periodMilliseconds)
: base(runner, delayMilliseconds, periodMilliseconds)
{
_messenger = messenger;
}
public override bool PerformRun()
{
_messenger.Sync();
//return true to repeat
return true;
}
public override bool IsAsync
{
get { return false; }
}
}
private void UmbracoModule_EndRequest(object sender, UmbracoRequestEventArgs e)
{
// will clear the batch - will remain in HttpContext though - that's ok
FlushBatch();
}
protected override void DeliverRemote(IEnumerable servers, ICacheRefresher refresher, MessageType messageType, IEnumerable