* Start work * Introduce dto * Start making repository * Add migrations * Implement fetchable first job * Fix up to also finish tasks * Refactor jobs to distributed background jobs * Filter jobs correctly on LastRun * Hardcode delay * Add settings to configure delay and period * Fix formatting * Add default data * Add update on startup, which will update periods on startup * Refactor service to return job directly * Update src/Umbraco.Infrastructure/Services/Implement/DistributedJobService.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/Umbraco.Infrastructure/BackgroundJobs/DistributedBackgroundJobHostedService.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/Umbraco.Infrastructure/BackgroundJobs/DistributedBackgroundJobHostedService.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Remove unused * Move jobs and make internal * make OpenIddictCleanupJob.cs public, as it is used elsewhere * Minor docstring changes * Update src/Umbraco.Core/Persistence/Constants-Locks.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * ´Throw correct exceptions * Update xml doc * Remove business logic from repository * Remove more business logic from repository into service * Remove adding jobs from migration * fix creation * Rename to ExecuteAsync --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
111 lines
4.4 KiB
C#
111 lines
4.4 KiB
C#
// Copyright (c) Umbraco.
|
|
// See LICENSE for more details.
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
using Umbraco.Cms.Core;
|
|
using Umbraco.Cms.Core.Scoping;
|
|
using Umbraco.Cms.Core.Services;
|
|
using Umbraco.Cms.Core.Sync;
|
|
using Umbraco.Cms.Core.Web;
|
|
|
|
namespace Umbraco.Cms.Infrastructure.BackgroundJobs.Jobs.DistributedJobs;
|
|
|
|
/// <summary>
|
|
/// Hosted service implementation for scheduled publishing feature.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Runs only on non-replica servers.
|
|
/// </remarks>
|
|
internal class ScheduledPublishingJob : IDistributedBackgroundJob
|
|
{
|
|
/// <inheritdoc />
|
|
public string Name => "ScheduledPublishingJob";
|
|
|
|
/// <inheritdoc />
|
|
public TimeSpan Period => TimeSpan.FromMinutes(1);
|
|
|
|
|
|
private readonly IContentService _contentService;
|
|
private readonly ILogger<ScheduledPublishingJob> _logger;
|
|
private readonly ICoreScopeProvider _scopeProvider;
|
|
private readonly TimeProvider _timeProvider;
|
|
private readonly IServerMessenger _serverMessenger;
|
|
private readonly IUmbracoContextFactory _umbracoContextFactory;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ScheduledPublishingJob" /> class.
|
|
/// </summary>
|
|
public ScheduledPublishingJob(
|
|
IContentService contentService,
|
|
IUmbracoContextFactory umbracoContextFactory,
|
|
ILogger<ScheduledPublishingJob> logger,
|
|
IServerMessenger serverMessenger,
|
|
ICoreScopeProvider scopeProvider,
|
|
TimeProvider timeProvider)
|
|
{
|
|
_contentService = contentService;
|
|
_umbracoContextFactory = umbracoContextFactory;
|
|
_logger = logger;
|
|
_serverMessenger = serverMessenger;
|
|
_scopeProvider = scopeProvider;
|
|
_timeProvider = timeProvider;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task ExecuteAsync()
|
|
{
|
|
if (Suspendable.ScheduledPublishing.CanRun == false)
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
try
|
|
{
|
|
// Ensure we run with an UmbracoContext, because this will run in a background task,
|
|
// and developers may be using the 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 UmbracoContextReference contextReference = _umbracoContextFactory.EnsureUmbracoContext();
|
|
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
|
|
|
|
/* We used to assume that there will never be two instances running concurrently where (IsMainDom && ServerRole == SchedulingPublisher)
|
|
* However this is possible during an azure deployment slot swap for the SchedulingPublisher instance when trying to achieve zero downtime deployments.
|
|
* If we take a distributed write lock, we are certain that the multiple instances of the job will not run in parallel.
|
|
* It's possible that during the swapping process we may run this job more frequently than intended but this is not of great concern and it's
|
|
* only until the old SchedulingPublisher shuts down. */
|
|
scope.EagerWriteLock(Constants.Locks.ScheduledPublishing);
|
|
try
|
|
{
|
|
// Run
|
|
IEnumerable<PublishResult> result = _contentService.PerformScheduledPublish(_timeProvider.GetUtcNow().UtcDateTime);
|
|
foreach (IGrouping<PublishResultType, PublishResult> grouped in result.GroupBy(x => x.Result))
|
|
{
|
|
_logger.LogInformation(
|
|
"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)
|
|
{
|
|
_serverMessenger.SendMessages();
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// important to catch *everything* to ensure the task repeats
|
|
_logger.LogError(ex, "Failed.");
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|