17
17
using System . Threading ;
18
18
using System . Threading . Tasks ;
19
19
using QuantConnect . Logging ;
20
+ using QuantConnect . Util ;
20
21
21
22
namespace QuantConnect
22
23
{
@@ -67,8 +68,38 @@ public Isolator()
67
68
/// <param name="codeBlock">Action codeblock to execute</param>
68
69
/// <param name="memoryCap">Maximum memory allocation, default 1024Mb</param>
69
70
/// <param name="sleepIntervalMillis">Sleep interval between each check in ms</param>
71
+ /// <param name="workerThread">The worker thread instance that will execute the provided action, if null
72
+ /// will use a <see cref="Task"/></param>
70
73
/// <returns>True if algorithm exited successfully, false if cancelled because it exceeded limits.</returns>
71
- public bool ExecuteWithTimeLimit ( TimeSpan timeSpan , Func < IsolatorLimitResult > withinCustomLimits , Action codeBlock , long memoryCap = 1024 , int sleepIntervalMillis = 1000 )
74
+ public bool ExecuteWithTimeLimit ( TimeSpan timeSpan , Func < IsolatorLimitResult > withinCustomLimits , Action codeBlock , long memoryCap = 1024 , int sleepIntervalMillis = 1000 , WorkerThread workerThread = null )
75
+ {
76
+ workerThread ? . Add ( codeBlock ) ;
77
+
78
+ var task = workerThread == null
79
+ //Launch task
80
+ ? Task . Factory . StartNew ( codeBlock , CancellationTokenSource . Token )
81
+ // wrapper task so we can reuse MonitorTask
82
+ : Task . Factory . StartNew ( ( ) => workerThread . FinishedWorkItem . WaitOne ( ) , CancellationTokenSource . Token ) ;
83
+ try
84
+ {
85
+ return MonitorTask ( task , timeSpan , withinCustomLimits , memoryCap , sleepIntervalMillis ) ;
86
+ }
87
+ catch ( Exception )
88
+ {
89
+ if ( ! task . IsCompleted )
90
+ {
91
+ // lets free the wrapper task even if the worker thread didn't finish
92
+ workerThread ? . FinishedWorkItem . Set ( ) ;
93
+ }
94
+ throw ;
95
+ }
96
+ }
97
+
98
+ private bool MonitorTask ( Task task ,
99
+ TimeSpan timeSpan ,
100
+ Func < IsolatorLimitResult > withinCustomLimits ,
101
+ long memoryCap = 1024 ,
102
+ int sleepIntervalMillis = 1000 )
72
103
{
73
104
// default to always within custom limits
74
105
withinCustomLimits = withinCustomLimits ?? ( ( ) => new IsolatorLimitResult ( TimeSpan . Zero , string . Empty ) ) ;
@@ -84,9 +115,6 @@ public bool ExecuteWithTimeLimit(TimeSpan timeSpan, Func<IsolatorLimitResult> wi
84
115
memoryCap *= 1024 * 1024 ;
85
116
var spikeLimit = memoryCap * 2 ;
86
117
87
- //Launch task
88
- var task = Task . Factory . StartNew ( codeBlock , CancellationTokenSource . Token ) ;
89
-
90
118
// give some granularity to the sleep interval if >= 1000ms
91
119
var sleepGranularity = sleepIntervalMillis >= 1000 ? 5 : 1 ;
92
120
var granularSleepIntervalMillis = sleepIntervalMillis / sleepGranularity ;
@@ -151,7 +179,7 @@ public bool ExecuteWithTimeLimit(TimeSpan timeSpan, Func<IsolatorLimitResult> wi
151
179
{
152
180
CancellationTokenSource . Cancel ( ) ;
153
181
Log . Error ( "Security.ExecuteWithTimeLimit(): " + message ) ;
154
- throw new Exception ( message ) ;
182
+ throw new TimeoutException ( message ) ;
155
183
}
156
184
return task . IsCompleted ;
157
185
}
@@ -163,10 +191,12 @@ public bool ExecuteWithTimeLimit(TimeSpan timeSpan, Func<IsolatorLimitResult> wi
163
191
/// <param name="codeBlock">Action codeblock to execute</param>
164
192
/// <param name="memoryCap">Maximum memory allocation, default 1024Mb</param>
165
193
/// <param name="sleepIntervalMillis">Sleep interval between each check in ms</param>
194
+ /// <param name="workerThread">The worker thread instance that will execute the provided action, if null
195
+ /// will use a <see cref="Task"/></param>
166
196
/// <returns>True if algorithm exited successfully, false if cancelled because it exceeded limits.</returns>
167
- public bool ExecuteWithTimeLimit ( TimeSpan timeSpan , Action codeBlock , long memoryCap , int sleepIntervalMillis = 1000 )
197
+ public bool ExecuteWithTimeLimit ( TimeSpan timeSpan , Action codeBlock , long memoryCap , int sleepIntervalMillis = 1000 , WorkerThread workerThread = null )
168
198
{
169
- return ExecuteWithTimeLimit ( timeSpan , null , codeBlock , memoryCap , sleepIntervalMillis ) ;
199
+ return ExecuteWithTimeLimit ( timeSpan , null , codeBlock , memoryCap , sleepIntervalMillis , workerThread ) ;
170
200
}
171
201
172
202
/// <summary>
0 commit comments