using System; using System.Linq; using System.Threading; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.ScheduledTasks.Triggers { /// /// Represents a task trigger that runs repeatedly on an interval. /// public sealed class IntervalTrigger : ITaskTrigger, IDisposable { private readonly TimeSpan _interval; private DateTime _lastStartDate; private Timer? _timer; private bool _disposed = false; /// /// Initializes a new instance of the class. /// /// The interval. /// The options of this task. public IntervalTrigger(TimeSpan interval, TaskOptions taskOptions) { _interval = interval; TaskOptions = taskOptions; } /// /// Occurs when [triggered]. /// public event EventHandler? Triggered; /// /// Gets the options of this task. /// public TaskOptions TaskOptions { get; } /// /// Stars waiting for the trigger action. /// /// The last result. /// The logger. /// The name of the task. /// if set to true [is application startup]. public void Start(TaskResult? lastResult, ILogger logger, string taskName, bool isApplicationStartup) { DisposeTimer(); DateTime triggerDate; if (lastResult is null) { // Task has never been completed before triggerDate = DateTime.UtcNow.AddHours(1); } else { triggerDate = new[] { lastResult.EndTimeUtc, _lastStartDate }.Max().Add(_interval); } if (DateTime.UtcNow > triggerDate) { triggerDate = DateTime.UtcNow.AddMinutes(1); } var dueTime = triggerDate - DateTime.UtcNow; var maxDueTime = TimeSpan.FromDays(7); if (dueTime > maxDueTime) { dueTime = maxDueTime; } _timer = new Timer(_ => OnTriggered(), null, dueTime, TimeSpan.FromMilliseconds(-1)); } /// /// Stops waiting for the trigger action. /// public void Stop() { DisposeTimer(); } /// /// Disposes the timer. /// private void DisposeTimer() { _timer?.Dispose(); _timer = null; } /// /// Called when [triggered]. /// private void OnTriggered() { DisposeTimer(); if (Triggered != null) { _lastStartDate = DateTime.UtcNow; Triggered(this, EventArgs.Empty); } } /// public void Dispose() { if (_disposed) { return; } DisposeTimer(); _disposed = true; } } }