Lean  $LEAN_TAG$
TimeMonitor.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System;
17 using System.Collections.Generic;
18 using System.Threading;
19 using QuantConnect.Util;
20 
22 {
23  /// <summary>
24  /// Helper class that will monitor timer consumers and request more time if required.
25  /// Used by <see cref="IsolatorLimitResultProvider"/>
26  /// </summary>
27  public class TimeMonitor : IDisposable
28  {
29  private readonly Timer _timer;
30  /// <summary>
31  /// List to store the coming TimeConsumer objects
32  /// </summary>
33  /// <remarks>This field is protected because it's used in a test class
34  /// in `IsolatorLimitResultProviderTests.cs</remarks>
35  protected List<TimeConsumer> TimeConsumers { get; init; }
36 
37  /// <summary>
38  /// Returns the number of time consumers currently being monitored
39  /// </summary>
40  public int Count
41  {
42  get
43  {
44  lock (TimeConsumers)
45  {
46  return TimeConsumers.Count;
47  }
48  }
49  }
50 
51  /// <summary>
52  /// Creates a new instance
53  /// </summary>
54  public TimeMonitor(int monitorIntervalMs = 100)
55  {
56  TimeConsumers = new List<TimeConsumer>();
57  _timer = new Timer(state =>
58  {
59  try
60  {
61  lock (TimeConsumers)
62  {
63  RemoveAll();
64 
65  foreach (var consumer in TimeConsumers)
66  {
67  ProcessConsumer(consumer);
68  }
69  }
70  }
71  finally
72  {
73  try
74  {
75  _timer.Change(Time.GetSecondUnevenWait(monitorIntervalMs), Timeout.Infinite);
76  }
77  catch (ObjectDisposedException)
78  {
79  // ignored disposed
80  }
81  }
82  }, null, monitorIntervalMs, Timeout.Infinite);
83  }
84 
85  /// <summary>
86  /// Process the TimeConsumer object in TimeConsumers list
87  /// </summary>
88  /// <param name="consumer">The TimeConsumer object to be processed</param>
89  /// <remarks>This method is protected because it's overrode by a test class
90  /// in `IsolatorLimitResultProviderTests.cs`</remarks>
91  protected virtual void ProcessConsumer(TimeConsumer consumer)
92  {
93  if (consumer.NextTimeRequest == null)
94  {
95  // first time, for performance we register this here and not the time consumer
96  consumer.NextTimeRequest = consumer.TimeProvider.GetUtcNow().AddMinutes(1);
97  }
98  else if (consumer.TimeProvider.GetUtcNow() >= consumer.NextTimeRequest)
99  {
100  // each minute request additional time from the isolator
101  consumer.NextTimeRequest = consumer.NextTimeRequest.Value.AddMinutes(1);
102  try
103  {
104  // this will notify the isolator that we've exceed the limits
105  consumer.IsolatorLimitProvider.RequestAdditionalTime(minutes: 1);
106  }
107  catch
108  {
109  // pass
110  }
111  }
112  }
113 
114  /// <summary>
115  /// Remove all TimeConsumer objects where the `Finished` field is marked as true
116  /// </summary>
117  /// <remarks>This method is protected because it's overrode by a test class in
118  /// `IsolatorLimitResultProviderTests.cs`</remarks>
119  protected virtual void RemoveAll()
120  {
121  TimeConsumers.RemoveAll(time => time.Finished);
122  }
123 
124  /// <summary>
125  /// Adds a new time consumer element to be monitored
126  /// </summary>
127  /// <param name="consumer">Time consumer instance</param>
128  public void Add(TimeConsumer consumer)
129  {
130  lock (TimeConsumers)
131  {
132  TimeConsumers.Add(consumer);
133  }
134  }
135 
136  /// <summary>
137  /// Disposes of the inner timer
138  /// </summary>
139  public void Dispose()
140  {
141  _timer.DisposeSafely();
142  }
143  }
144 }