18 private const NumberStyles DoubleParseStyle = NumberStyles.AllowDecimalPoint;
19 private static readonly CultureInfo ParseCulture = CultureInfo.InvariantCulture;
21 #region Private Fields
22 private readonly ConcurrentDictionary<string, SimulationStatus> _simulations;
23 #endregion Private Fields
32 private int _numActivePolls = 0;
35 #endregion Public Fields
51 #endregion Public Events
57 _simulations =
new ConcurrentDictionary<string, SimulationStatus>();
59 #endregion Constructor
61 #region Public Control Methods
65 foreach (
SimulationStatus active
in _simulations.Where(sim => sim.Value.BeingPolled)
66 .Select(kvp => kvp.Value))
68 active.BeingPolled =
false;
69 active.Exception =
new Exception(
"Monitoring Cancelled.");
77 _simulations.Values.ToList().ForEach(sim =>
78 sim.SimulationStatusChanged -= OnSimulationStatusChanged);
81 #endregion Public Control Methods
83 #region Event Monitoring
94 Thread t =
new Thread(() => PollSimulationResultsUntilReady(
this, view, simulationRequest,
MaxPollInterval));
98 private void OnSimulationStatusChanged(
object sender, EventArgs e)
102 #endregion Event Monitoring
104 #region Threaded polling
108 SimulationStatus status =
new SimulationStatus(view.
id) { BeingPolled =
true };
109 bool added = owner._simulations.TryAdd(view.
id, status);
112 status.Description = view is PortfolioView ?
"Portfolio (" + ((PortfolioView)view).layer_views.Count +
" layer" + (((PortfolioView)view).layer_views.Count > 1 ?
"s)" :
")")
113 : view is ILayerView ? ((ILayerView)view).layer.type +
" Layer" + (String.IsNullOrWhiteSpace(((ILayerView)view).layer.description) ?
"" :
" \"" + ((ILayerView)view).layer.description +
"\"") : null;
114 owner.SimulationStatusAdded?.Invoke(owner, status);
115 status.SimulationStatusChanged += owner.OnSimulationStatusChanged;
119 status = owner._simulations[view.
id];
121 if (status.BeingPolled || status.State == SimulationStatus.SimulationState.Complete)
125 status.BeingPolled =
true;
126 status.Exception =
null;
130 if (status.BeingPolled) status.State = SimulationStatus.SimulationState.Queued;
132 Interlocked.Increment(ref owner._numActivePolls);
133 while (status.BeingPolled)
139 Interlocked.Decrement(ref owner._numActivePolls);
140 status.TimeRemaining = 0;
141 status.State = SimulationStatus.SimulationState.Complete;
142 status.BeingPolled =
false;
144 catch (APIRequestException e)
148 if (e.RestResponse ==
null ||
149 e.RestResponse.StatusCode != HttpStatusCode.ServiceUnavailable)
151 Parameter retryAfter = e.RestResponse.Headers.FirstOrDefault(header =>
152 header.Name.Equals(
"Retry-After", StringComparison.OrdinalIgnoreCase));
154 if (retryAfter ==
null)
157 if (!Double.TryParse(retryAfter.Value.ToString(), DoubleParseStyle, ParseCulture, out
double retryAfterSeconds))
158 throw new Exception(
"The server provided a Retry-After header, " +
159 "but it could not be parsed: " + retryAfter.Value, e);
161 status.TimeRemaining = retryAfterSeconds;
162 double nextSleep_seconds = Math.Min(maxPollInterval, retryAfterSeconds);
163 Thread.Sleep((
int)(1000 * nextSleep_seconds));
167 Interlocked.Decrement(ref owner._numActivePolls);
168 status.Exception = ex;
169 status.BeingPolled =
false;
172 catch (TimeoutException ex)
175 if (timeouts >= owner.MaxTimeouts)
177 Interlocked.Decrement(ref owner._numActivePolls);
178 status.Exception = ex;
179 status.BeingPolled =
false;
184 Interlocked.Decrement(ref owner._numActivePolls);
185 status.Exception = ex;
186 status.BeingPolled =
false;
190 #endregion Threaded polling