185 List<Action> running = workflows.ToList();
190 GPAL.
PublishSimpleEvent(GPALEventType.INFO, $
"Running [{running.Count}] workflow(s), [{maxAtOnce}] at a time, [{staggerMs}] ms apart.",
this, GPALObjectType.Browser);
193 object startLine =
new object();
194 DateTime lastStart = DateTime.MinValue;
199 SemaphoreSlim gate =
new SemaphoreSlim(maxAtOnce, maxAtOnce);
201 Task[] started = running.Select((workflow, index) => Task.Run(() =>
211 TimeSpan gap = TimeSpan.FromMilliseconds(staggerMs);
212 TimeSpan since = DateTime.Now - lastStart;
216 Thread.Sleep(gap - since);
218 lastStart = DateTime.Now;
224 DateTime began = DateTime.Now;
229 mine.Succeeded = true;
235 GPAL.
PublishSimpleEvent(GPALEventType.EXCEPTION, $
"Workflow [{index + 1}] failed",
this, GPALObjectType.Browser, ex);
239 mine.Duration = DateTime.Now - began;
244 bool allFinished = Task.WaitAll(started, timeoutMs);
251 Succeeded = run.Succeeded,
252 Duration = run.Duration,
253 Failure = run.Failure ?? (
true == run.Succeeded ? null :
new TimeoutException($
"Workflow [{run.Index + 1}] was still running after [{timeoutMs}] ms")),
256 if (
true == allFinished)
260 GPAL.
PublishSimpleEvent(GPALEventType.INFO, $
"All [{running.Count}] workflow(s) finished, [{runs.Count(r => false == r.Succeeded)}] of them failed.",
this, GPALObjectType.Browser);
265 GPAL.PublishSimpleEvent(GPALEventType.WARNING,
266 $
"Gave up waiting after [{timeoutMs}] ms with [{runs.Count(r => false == r.Succeeded)}] of [{running.Count}] workflow(s) still running. They keep going and keep their browsers.",
267 this, GPALObjectType.Browser);