public static void StartRunningProcesses() { if (running) { throw new InvalidOperationException("ProcessLogic is running"); } using (ExecutionContext.SuppressFlow()) Task.Factory.StartNew(() => { var database = Schema.Current.Table(typeof(ProcessEntity)).Name.Schema?.Database; SystemEventLogLogic.Log("Start ProcessRunner"); ExceptionEntity?exception = null; using (AuthLogic.Disable()) { try { running = true; (from p in Database.Query <ProcessEntity>() where p.IsMine() && (p.State == ProcessState.Executing || p.State == ProcessState.Suspending || p.State == ProcessState.Suspended) || p.IsShared() && p.State == ProcessState.Suspended select p).SetAsQueued(); CancelNewProcesses = new CancellationTokenSource(); autoResetEvent.Set(); timerNextExecution = new Timer(ob => WakeUp("TimerNextExecution", null), // main timer null, Timeout.Infinite, Timeout.Infinite); if (!CacheLogic.WithSqlDependency) { timerPeriodic = new Timer(ob => WakeUp("TimerPeriodic", null), null, PoolingPeriodMilliseconds, PoolingPeriodMilliseconds); } while (autoResetEvent.WaitOne()) { if (CancelNewProcesses.IsCancellationRequested) { return; } using (HeavyProfiler.Log("PWL", () => "Process Runner")) { (from p in Database.Query <ProcessEntity>() where p.State == ProcessState.Planned && p.PlannedDate <= Clock.Now select p).SetAsQueued(); var list = Database.Query <ProcessEntity>() .Where(p => p.IsMine() || p.IsShared()) .Where(p => p.State == ProcessState.Planned) .Select(p => p.PlannedDate) .ToListWakeup("Planned dependency"); SetNextPannedExecution(list.Min()); lock (executing) { int remaining = MaxDegreeOfParallelism - executing.Count; if (remaining > 0) { retry: var queued = Database.Query <ProcessEntity>() .Where(p => p.State == ProcessState.Queued) .Where(p => p.IsMine() || p.IsShared()) .Select(a => new { Process = a.ToLite(), a.QueuedDate, a.MachineName }) .ToListWakeup("Planned dependency"); var afordable = queued .OrderByDescending(p => p.MachineName == Environment.MachineName) .OrderBy(a => a.QueuedDate) .Take(remaining).ToList(); var taken = afordable.Where(p => p.MachineName == ProcessEntity.None).Select(a => a.Process).ToList(); if (taken.Any()) { using (var tr = Transaction.ForceNew()) { Database.Query <ProcessEntity>() .Where(p => taken.Contains(p.ToLite()) && p.MachineName == ProcessEntity.None) .UnsafeUpdate() .Set(p => p.MachineName, p => Environment.MachineName) .Set(p => p.ApplicationName, p => Schema.Current.ApplicationName) .Execute(); tr.Commit(); } goto retry; } foreach (var pair in afordable) { ProcessEntity pro = pair.Process !.RetrieveAndRemember(); IProcessAlgorithm algorithm = ProcessLogic.GetProcessAlgorithm(pro.Algorithm); ExecutingProcess executingProcess = new ExecutingProcess(algorithm, pro); executing.Add(pro.ToLite(), executingProcess); executingProcess.TakeForThisMachine(); using (ExecutionContext.SuppressFlow()) Task.Run(() => { try { executingProcess.Execute(); } catch (Exception ex) { try { ex.LogException(edn => { edn.ControllerName = "ProcessWorker"; edn.ActionName = executingProcess.CurrentProcess.ToLite().Key(); }); } catch { } } finally { lock (executing) { executing.Remove(pro.ToLite()); WakeUp("Process ended", null); } } }); } var suspending = Database.Query <ProcessEntity>() .Where(p => p.State == ProcessState.Suspending) .Where(p => p.IsMine()) .Select(a => a.ToLite()) .ToListWakeup("Suspending dependency"); foreach (var s in suspending) { ExecutingProcess execProc = executing.GetOrThrow(s); if (execProc.CurrentProcess.State != ProcessState.Finished) { execProc.CurrentProcess = s.RetrieveAndRemember(); execProc.CancelationSource.Cancel(); } } } } } } } catch (ThreadAbortException) { //Ignore } catch (Exception e) { try { exception = e.LogException(edn => { edn.ControllerName = "ProcessWorker"; edn.ActionName = "MainLoop"; }); } catch { } } finally { lock (executing) executing.Clear(); SystemEventLogLogic.Log("Stop ProcessRunner", exception); running = false; } } }, TaskCreationOptions.LongRunning); }