Refactored logic for calculating the first run time for a recurring hosted service. (#12828)
* Refactors the logic for calculating the first run time for a recurring task for easier re-use by similar hostservices. * Renamed method to match wider usage.
This commit is contained in:
@@ -3,6 +3,9 @@ using Umbraco.Cms.Core.Configuration.Models;
|
||||
|
||||
namespace Umbraco.Extensions;
|
||||
|
||||
// TODO (V12): Remove this class that's no longer used.
|
||||
|
||||
[Obsolete("Please use RecurringHostedServiceBase.GetDelay(). This class is no longer used within Umbraco and will be removed in V12.")]
|
||||
public static class HealthCheckSettingsExtensions
|
||||
{
|
||||
public static TimeSpan GetNotificationDelay(this HealthChecksSettings settings, ICronTabParser cronTabParser, DateTime now, TimeSpan defaultDelay)
|
||||
|
||||
@@ -2,8 +2,12 @@ using NCrontab;
|
||||
|
||||
namespace Umbraco.Cms.Core.Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Implements <see cref="ICronTabParser"/> using the NCrontab library
|
||||
/// </summary>
|
||||
public class NCronTabParser : ICronTabParser
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public bool IsValidCronTab(string cronTab)
|
||||
{
|
||||
var result = CrontabSchedule.TryParse(cronTab);
|
||||
@@ -11,6 +15,7 @@ public class NCronTabParser : ICronTabParser
|
||||
return !(result is null);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime GetNextOccurrence(string cronTab, DateTime time)
|
||||
{
|
||||
var result = CrontabSchedule.Parse(cronTab);
|
||||
|
||||
@@ -59,7 +59,7 @@ public class HealthCheckNotifier : RecurringHostedServiceBase
|
||||
: base(
|
||||
logger,
|
||||
healthChecksSettings.CurrentValue.Notification.Period,
|
||||
healthChecksSettings.CurrentValue.GetNotificationDelay(cronTabParser, DateTime.Now, DefaultDelay))
|
||||
GetDelay(healthChecksSettings.CurrentValue.Notification.FirstRunTime, cronTabParser, logger, DefaultDelay))
|
||||
{
|
||||
_healthChecksSettings = healthChecksSettings.CurrentValue;
|
||||
_healthChecks = healthChecks;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.HostedServices;
|
||||
|
||||
@@ -58,6 +59,60 @@ public abstract class RecurringHostedServiceBase : IHostedService, IDisposable
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the delay before the first run of a recurring task implemented as a hosted service when an optonal
|
||||
/// configuration for the first run time is available.
|
||||
/// </summary>
|
||||
/// <param name="firstRunTime">The configured time to first run the task in crontab format.</param>
|
||||
/// <param name="cronTabParser">An instance of <see cref="ICronTabParser"/></param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="defaultDelay">The default delay to use when a first run time is not configured.</param>
|
||||
/// <returns>The delay before first running the recurring task.</returns>
|
||||
protected static TimeSpan GetDelay(
|
||||
string firstRunTime,
|
||||
ICronTabParser cronTabParser,
|
||||
ILogger logger,
|
||||
TimeSpan defaultDelay) => GetDelay(firstRunTime, cronTabParser, logger, DateTime.Now, defaultDelay);
|
||||
|
||||
/// <summary>
|
||||
/// Determines the delay before the first run of a recurring task implemented as a hosted service when an optonal
|
||||
/// configuration for the first run time is available.
|
||||
/// </summary>
|
||||
/// <param name="firstRunTime">The configured time to first run the task in crontab format.</param>
|
||||
/// <param name="cronTabParser">An instance of <see cref="ICronTabParser"/></param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="now">The current datetime.</param>
|
||||
/// <param name="defaultDelay">The default delay to use when a first run time is not configured.</param>
|
||||
/// <returns>The delay before first running the recurring task.</returns>
|
||||
/// <remarks>Internal to expose for unit tests.</remarks>
|
||||
internal static TimeSpan GetDelay(
|
||||
string firstRunTime,
|
||||
ICronTabParser cronTabParser,
|
||||
ILogger logger,
|
||||
DateTime now,
|
||||
TimeSpan defaultDelay)
|
||||
{
|
||||
// If first run time not set, start with just small delay after application start.
|
||||
if (string.IsNullOrEmpty(firstRunTime))
|
||||
{
|
||||
return defaultDelay;
|
||||
}
|
||||
|
||||
// If first run time not a valid cron tab, log, and revert to small delay after application start.
|
||||
if (!cronTabParser.IsValidCronTab(firstRunTime))
|
||||
{
|
||||
logger.LogWarning("Could not parse {FirstRunTime} as a crontab expression. Defaulting to default delay for hosted service start.", firstRunTime);
|
||||
return defaultDelay;
|
||||
}
|
||||
|
||||
// Otherwise start at scheduled time according to cron expression, unless within the default delay period.
|
||||
DateTime firstRunOccurance = cronTabParser.GetNextOccurrence(firstRunTime, now);
|
||||
TimeSpan delay = firstRunOccurance - now;
|
||||
return delay < defaultDelay
|
||||
? defaultDelay
|
||||
: delay;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user