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; } /// public event EventHandler? Triggered; /// public TaskOptions TaskOptions { get; } /// public void Start(TaskResult? lastResult, ILogger logger, string taskName, bool isApplicationStartup) { DisposeTimer(); DateTime now = DateTime.UtcNow; DateTime triggerDate; if (lastResult is null) { // Task has never been completed before triggerDate = now.AddHours(1); } else { triggerDate = new[] { lastResult.EndTimeUtc, _lastStartDate, now.AddMinutes(1) }.Max().Add(_interval); } var dueTime = triggerDate - now; var maxDueTime = TimeSpan.FromDays(7); if (dueTime > maxDueTime) { dueTime = maxDueTime; } _timer = new Timer(_ => OnTriggered(), null, dueTime, TimeSpan.FromMilliseconds(-1)); } /// public void Stop() { DisposeTimer(); } /// /// Disposes the timer. /// private void DisposeTimer() { _timer?.Dispose(); _timer = null; } /// /// Called when [triggered]. /// private void OnTriggered() { DisposeTimer(); if (Triggered is not null) { _lastStartDate = DateTime.UtcNow; Triggered(this, EventArgs.Empty); } } /// public void Dispose() { if (_disposed) { return; } DisposeTimer(); _disposed = true; } } }