Files
Umbraco-CMS/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs
2019-02-14 12:11:06 +01:00

96 lines
4.0 KiB
C#

using System;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Services;
using Umbraco.Core.Sync;
namespace Umbraco.Web.Scheduling
{
internal class ScheduledPublishing : RecurringTaskBase
{
private readonly IRuntimeState _runtime;
private readonly IContentService _contentService;
private readonly IUmbracoContextFactory _umbracoContextFactory;
private readonly ILogger _logger;
public ScheduledPublishing(IBackgroundTaskRunner<RecurringTaskBase> runner, int delayMilliseconds, int periodMilliseconds,
IRuntimeState runtime, IContentService contentService, IUmbracoContextFactory umbracoContextFactory, ILogger logger)
: base(runner, delayMilliseconds, periodMilliseconds)
{
_runtime = runtime;
_contentService = contentService;
_umbracoContextFactory = umbracoContextFactory;
_logger = logger;
}
public override bool PerformRun()
{
if (Suspendable.ScheduledPublishing.CanRun == false)
return true; // repeat, later
switch (_runtime.ServerRole)
{
case ServerRole.Replica:
_logger.Debug<ScheduledPublishing>("Does not run on replica servers.");
return true; // DO repeat, server role can change
case ServerRole.Unknown:
_logger.Debug<ScheduledPublishing>("Does not run on servers with unknown role.");
return true; // DO repeat, server role can change
}
// ensure we do not run if not main domain, but do NOT lock it
if (_runtime.IsMainDom == false)
{
_logger.Debug<ScheduledPublishing>("Does not run if not MainDom.");
return false; // do NOT repeat, going down
}
// do NOT run publishing if not properly running
if (_runtime.Level != RuntimeLevel.Run)
{
_logger.Debug<ScheduledPublishing>("Does not run if run level is not Run.");
return true; // repeat/wait
}
try
{
// ensure we run with an UmbracoContext, because this may run in a background task,
// yet developers may be using the 'current' UmbracoContext in the event handlers
//
// TODO: or maybe not, CacheRefresherComponent already ensures a context when handling events
// - UmbracoContext 'current' needs to be refactored and cleaned up
// - batched messenger should not depend on a current HttpContext
// but then what should be its "scope"? could we attach it to scopes?
// - and we should definitively *not* have to flush it here (should be auto)
//
using (var contextReference = _umbracoContextFactory.EnsureUmbracoContext())
{
try
{
// run
var result = _contentService.PerformScheduledPublish(DateTime.Now);
foreach (var grouped in result.GroupBy(x => x.Result))
_logger.Info<ScheduledPublishing>("Scheduled publishing result: '{StatusCount}' items with status {Status}", grouped.Count(), grouped.Key);
}
finally
{
// if running on a temp context, we have to flush the messenger
if (contextReference.IsRoot && Composing.Current.ServerMessenger is BatchedDatabaseServerMessenger m)
m.FlushBatch();
}
}
}
catch (Exception ex)
{
// important to catch *everything* to ensure the task repeats
_logger.Error<ScheduledPublishing>(ex, "Failed.");
}
return true; // repeat
}
public override bool IsAsync => false;
}
}