Beispiel #1
0
        public static void Register(ProcessAlgorithmSymbol processAlgorithm, IProcessAlgorithm algorithm)
        {
            if (processAlgorithm == null)
            {
                throw AutoInitAttribute.ArgumentNullException(typeof(ProcessAlgorithmSymbol), nameof(processAlgorithm));
            }

            if (algorithm == null)
            {
                throw new ArgumentNullException(nameof(algorithm));
            }

            registeredProcesses.Add(processAlgorithm, algorithm);
        }
Beispiel #2
0
 public ExecutingProcess(IProcessAlgorithm processAlgorithm, ProcessEntity process)
 {
     this.CancelationSource = new CancellationTokenSource();
     this.Algorithm         = processAlgorithm;
     this.CurrentProcess    = process;
 }
Beispiel #3
0
        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 <= TimeZoneManager.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 (Transaction 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.Retrieve();

                                                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.Retrieve();
                                                    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);
        }