/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Threading; using System.Threading.Tasks; using QuantConnect.Util; namespace QuantConnect.Lean.Engine.DataFeeds { /// /// Allows to setup a real time scheduled event, internally using a , /// that is guaranteed to trigger at or after the requested time, never before. /// /// This class is of value because could fire the /// event before time. public class RealTimeScheduleEventService : IDisposable { private readonly Timer _timer; private readonly Ref _nextUtcScheduledEvent; /// /// Event fired when the scheduled time is past /// public event EventHandler NewEvent; /// /// Creates a new instance /// /// The time provider to use public RealTimeScheduleEventService(ITimeProvider timeProvider) { _nextUtcScheduledEvent = Ref.Create(DateTime.MinValue); _timer = new Timer( async state => { var nextUtcScheduledEvent = ((Ref)state).Value; var diff = nextUtcScheduledEvent - timeProvider.GetUtcNow(); // we need to guarantee we trigger the event after the requested due time // has past, if we got called earlier lets wait until time is right while (diff.Ticks > 0) { await Task.Delay(diff); // testing has shown that it sometimes requires more than one loop diff = nextUtcScheduledEvent - timeProvider.GetUtcNow(); } NewEvent?.Invoke(this, EventArgs.Empty); }, _nextUtcScheduledEvent, // Due time is never, has to be scheduled Timeout.InfiniteTimeSpan, // Do not trigger periodically Timeout.InfiniteTimeSpan); } /// /// Schedules a new event /// /// The desired due time /// Current utc time /// Scheduling a new event will try to disable previous scheduled event, /// but it is not guaranteed. public void ScheduleEvent(TimeSpan dueTime, DateTime utcNow) { _nextUtcScheduledEvent.Value = utcNow + dueTime; _timer.Change(dueTime, Timeout.InfiniteTimeSpan); } /// /// Disposes of the underlying instance /// public void Dispose() { _timer.Dispose(); } } }