Browse Source

add executors to common

arthur.wu 2 years ago
parent
commit
ecd85a88cf

+ 103 - 0
Utilities/Executors/DynamicExecutor.cs

@@ -0,0 +1,103 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace WingServerCommon.Utilities.Executors
+{
+    /// <summary>
+    /// The DynamicExecutor provide the ability that can active one worker and let it run first.
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public class DynamicExecutor<T> : ExecutorBase<T> where T : class, IIdContext
+    {
+        private readonly List<ExecuteWorker<T>> _workers = new List<ExecuteWorker<T>>();
+
+        public DynamicExecutor(string name) : base(name)
+        {
+        }
+
+        protected DynamicExecutor(string name, TimeSpan executeDelayTime) : base(name, executeDelayTime)
+        {
+        }
+
+        /// <summary>
+        /// Activate one worker so that it can run first.
+        /// </summary>
+        /// <param name="contextId"></param>
+        public void ActivateWorker(string contextId)
+        {
+            lock (WorkersLocker)
+            {
+                var worker = _workers.FirstOrDefault(x => x.Parameter.Id == contextId);
+                if (worker != null && _workers.IndexOf(worker) != 0)
+                {
+                    _workers.Remove(worker);
+                    _workers.Insert(0, worker);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Indicate whether all works already contain the item.
+        /// </summary>
+        /// <param name="contextId">context id.</param>
+        /// <returns>True if contains.</returns>
+        public bool ContainsWorker(string contextId)
+        {
+            lock (WorkersLocker)
+            {
+                return _workers.Any(m => m.Parameter.Id == contextId);
+            }
+        }
+
+
+        /// <summary>
+        /// Gets current worker count in queue.
+        /// </summary>
+        /// <returns></returns>
+        protected override int GetWorkerCount()
+        {
+            return _workers.Count;
+        }
+
+        /// <summary>
+        /// Add one worker into the queue.
+        /// </summary>
+        /// <param name="worker"></param>
+        protected override void AddWorker(ExecuteWorker<T> worker)
+        {
+            _workers.Add(worker);
+        }
+
+        /// <summary>
+        /// Take one worker from the queue.
+        /// </summary>
+        /// <returns></returns>
+        protected override ExecuteWorker<T> TakeWorker()
+        {
+            var worker = _workers.FirstOrDefault();
+            if (worker != null)
+            {
+                _workers.Remove(worker);
+            }
+            return worker;
+        }
+
+        /// <summary>
+        /// Gets all workers.
+        /// </summary>
+        /// <returns></returns>
+        protected override IEnumerable<ExecuteWorker<T>> GetWorkers()
+        {
+            return _workers.ToArray();
+        }
+
+        /// <summary>
+        /// Clear all workers which not stated.
+        /// </summary>
+        protected override void CancelWorkers()
+        {
+            _workers.Clear();
+        }
+    }
+}

+ 35 - 0
Utilities/Executors/ExecuteWorker.cs

@@ -0,0 +1,35 @@
+using System;
+
+namespace WingServerCommon.Utilities.Executors
+{
+    public class ExecuteWorker<T> where T : class
+    {
+        public T Parameter { get; }
+
+        private readonly Func<T, bool> _executeMethod;
+
+        /// <summary>
+        /// Run the Action of this worker.
+        /// </summary>
+        ///<returns>If False the follow workers will not run, if ture it will be continue run.</returns>
+        public bool Run()
+        {
+            if (_executeMethod != null)
+            {
+                return _executeMethod(Parameter);
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Run the worker.
+        /// </summary>
+        /// <param name="executeMethod">The run func implementation.</param>
+        /// <param name="parameter">The parameter which will pass to the func.</param>
+        public ExecuteWorker(Func<T, bool> executeMethod, T parameter)
+        {
+            Parameter = parameter;
+            _executeMethod = executeMethod;
+        }
+    }
+}

+ 57 - 0
Utilities/Executors/ExecutingStatus.cs

@@ -0,0 +1,57 @@
+using System;
+using System.Threading;
+
+namespace WingServerCommon.Utilities.Executors
+{
+    public class ExecutingStatus
+    {
+        private readonly ManualResetEvent _executingEvent = new ManualResetEvent(true);
+        private volatile bool _executing;
+
+        /// <summary>
+        /// Gets the status if is executing.
+        /// </summary>
+        public bool Executing
+        {
+            get => _executing;
+            private set => _executing = value;
+        }
+
+        public ExecutingStatus()
+        {
+            _executingEvent.Set();
+            Executing = false;
+        }
+
+        /// <summary>
+        /// Reset the status.
+        /// </summary>
+        public void Reset()
+        {
+            _executingEvent.Reset();
+            Executing = true;
+        }
+
+        /// <summary>
+        /// Set the status.
+        /// </summary>
+        public void Set()
+        {
+            Executing = false;
+            _executingEvent.Set();
+        }
+
+        /// <summary>
+        /// Wait for the status to set.
+        /// </summary>
+        public void Wait()
+        {
+            _executingEvent.WaitOne();
+        }
+
+        public void Wait(double secondsTimeout)
+        {
+            _executingEvent.WaitOne(TimeSpan.FromSeconds(secondsTimeout));
+        }
+    }
+}

+ 203 - 0
Utilities/Executors/ExecutorBase.cs

@@ -0,0 +1,203 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace WingServerCommon.Utilities.Executors
+{
+    public abstract class ExecutorBase<T> where T : class
+    {
+        private readonly TimeSpan _executeDelayTime;
+        protected readonly object WorkersLocker = new object();
+        private volatile bool _closed;
+        private readonly ExecutingStatus _executingStatus = new ExecutingStatus();
+        private readonly ManualResetEvent _delayManualResetEvent = new ManualResetEvent(false);
+
+        /// <summary>
+        /// Gets the name of this executor.
+        /// </summary>
+        public string Name { get; }
+
+        /// <summary>
+        /// Gets all workers count.
+        /// </summary>
+        public int WorkerCount => GetWorkerCount();
+
+        /// <summary>
+        /// Indicate this executor is closed
+        /// </summary>
+        public bool IsClosed => _closed;
+
+        protected ExecutorBase(string name)
+        {
+            _executeDelayTime = TimeSpan.MinValue;
+            Name = name;
+        }
+
+        protected ExecutorBase(string name, TimeSpan executeDelayTime) : this(name)
+        {
+            _executeDelayTime = executeDelayTime;
+        }
+
+        /// <summary>
+        /// Gets current worker count in queue.
+        /// </summary>
+        /// <returns></returns>
+        protected abstract int GetWorkerCount();
+
+        /// <summary>
+        /// Add one worker into the queue.
+        /// </summary>
+        /// <param name="worker"></param>
+        protected abstract void AddWorker(ExecuteWorker<T> worker);
+
+        /// <summary>
+        /// Take one worker from the queue.
+        /// </summary>
+        /// <returns></returns>
+        protected abstract ExecuteWorker<T> TakeWorker();
+
+        /// <summary>
+        /// Gets all workers.
+        /// </summary>
+        /// <returns></returns>
+        protected abstract IEnumerable<ExecuteWorker<T>> GetWorkers();
+
+        /// <summary>
+        /// Clear all workers which not stated.
+        /// </summary>
+        protected abstract void CancelWorkers();
+
+        /// <summary>
+        /// Add one execute func into the queue.
+        /// </summary>
+        /// <param name="executeMethod"></param>
+        /// <param name="parameter"></param>
+        public void Add(Func<T, bool> executeMethod, T parameter)
+        {
+            lock (WorkersLocker)
+            {
+                if (_closed)
+                {
+                    return;
+                }
+
+                var worker = new ExecuteWorker<T>(executeMethod, parameter);
+                AddWorker(worker);
+                if (!_executingStatus.Executing)
+                {
+                    _executingStatus.Reset();
+                    DoExecute();
+                }
+            }
+        }
+
+        /// <summary>
+        /// The final method to run the worker.
+        /// </summary>
+        private void DoExecute()
+        {
+            //Logic mush run in another thread.
+            Task.Run(() =>
+            {
+                ExecuteWorker<T> worker = null;
+                lock (WorkersLocker)
+                {
+                    if (WorkerCount > 0)
+                    {
+                        worker = TakeWorker();
+                    }
+                }
+
+                var executeResult = worker?.Run() ?? true;
+
+                if (_closed)
+                {
+                    _executingStatus.Set();
+                }
+
+                lock (WorkersLocker)
+                {
+                    var continueExecute = WorkerCount > 0 && !_closed && executeResult;
+                    if (continueExecute)
+                    {
+                        if (_executeDelayTime != TimeSpan.MinValue)
+                        {
+                            _delayManualResetEvent.WaitOne(_executeDelayTime);
+                        }
+
+                        DoExecute();
+                    }
+                    else
+                    {
+                        _executingStatus.Set();
+                    }
+                }
+            });
+        }
+
+        /// <summary>
+        /// Close the executor and execute all workers.
+        /// </summary>
+        public void Close()
+        {
+            StopExecuting();
+            lock (WorkersLocker)
+            {
+                var workers = GetWorkers();
+                foreach (var worker in workers)
+                {
+                    worker?.Run();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Dispose current executor.
+        /// </summary>
+        public void Dispose(int timeoutSeconds = 10)
+        {
+            _closed = true;
+            lock (WorkersLocker)
+            {
+                CancelWorkers();
+                _executingStatus.Wait(timeoutSeconds);
+            }
+        }
+
+        /// <summary>
+        /// Cancel all workers.
+        /// </summary>
+        public void Cancel()
+        {
+            lock (WorkersLocker)
+            {
+                CancelWorkers();
+            }
+            StopExecuting();
+        }
+
+        /// <summary>
+        /// Stop executing.
+        /// </summary>
+        protected void StopExecuting()
+        {
+            _closed = true;
+            lock (WorkersLocker)
+            {
+                if (WorkerCount == 0)
+                {
+                    _closed = false;
+                    return;
+                }
+                _executingStatus.Wait();
+            }
+            _closed = false;
+        }
+
+        public bool GetExecutingStatus()
+        {
+            return _executingStatus.Executing;
+        }
+    }
+}

+ 10 - 0
Utilities/Executors/IIdContext.cs

@@ -0,0 +1,10 @@
+namespace WingServerCommon.Utilities.Executors
+{
+    public interface IIdContext
+    {
+        /// <summary>
+        /// Gets the Id of this context.
+        /// </summary>
+        string Id { get; }
+    }
+}

+ 76 - 0
Utilities/Executors/SequenceExecutor.cs

@@ -0,0 +1,76 @@
+using System;
+using System.Collections.Generic;
+
+namespace WingServerCommon.Utilities.Executors
+{
+    /// <summary>
+    /// This executor will run workers one by one.
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public class SequenceExecutor<T> : ExecutorBase<T> where T : class
+    {
+        private readonly Queue<ExecuteWorker<T>> _workers = new Queue<ExecuteWorker<T>>();
+
+        public SequenceExecutor(string name) : base(name)
+        {
+        }
+
+        public SequenceExecutor(string name, TimeSpan executeDelayTime) : base(name, executeDelayTime)
+        {
+        }
+
+        /// <summary>
+        /// Gets current worker count in queue.
+        /// </summary>
+        /// <returns></returns>
+        protected override int GetWorkerCount()
+        {
+            return _workers.Count;
+        }
+
+        /// <summary>
+        /// Add one worker into the queue.
+        /// </summary>
+        /// <param name="worker"></param>
+        protected override void AddWorker(ExecuteWorker<T> worker)
+        {
+            _workers.Enqueue(worker);
+        }
+
+        /// <summary>
+        /// Take one worker from the queue.
+        /// </summary>
+        /// <returns></returns>
+        protected override ExecuteWorker<T> TakeWorker()
+        {
+            return _workers.Dequeue();
+        }
+
+        /// <summary>
+        /// Gets all workers.
+        /// </summary>
+        /// <returns></returns>
+        protected override IEnumerable<ExecuteWorker<T>> GetWorkers()
+        {
+            return _workers.ToArray();
+        }
+
+        /// <summary>
+        /// Clear all workers which not stated.
+        /// </summary>
+        protected override void CancelWorkers()
+        {
+            _workers.Clear();
+        }
+
+        /// <summary>
+        /// Get the rest not working workers
+        /// </summary>
+        /// <returns></returns>
+        public IEnumerable<ExecuteWorker<T>> GetRestWorkers()
+        {
+            return GetWorkers();
+        }
+
+    }
+}

+ 62 - 0
Utilities/Executors/StackExecutor.cs

@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+
+namespace WingServerCommon.Utilities.Executors
+{
+    class StackExecutor<T> : ExecutorBase<T> where T : class
+    {
+        private readonly Stack<ExecuteWorker<T>> _workers = new Stack<ExecuteWorker<T>>();
+
+        public StackExecutor(string name) : base(name)
+        {
+        }
+
+        protected StackExecutor(string name, TimeSpan executeDelayTime) : base(name, executeDelayTime)
+        {
+        }
+
+        /// <summary>
+        /// Gets current worker count in stack.
+        /// </summary>
+        /// <returns></returns>
+        protected override int GetWorkerCount()
+        {
+            return _workers.Count;
+        }
+
+        /// <summary>
+        /// Add one worker into the stack.
+        /// </summary>
+        /// <param name="worker"></param>
+        protected override void AddWorker(ExecuteWorker<T> worker)
+        {
+            _workers.Push(worker);
+        }
+
+        /// <summary>
+        /// Take one worker from the stack.
+        /// </summary>
+        /// <returns></returns>
+        protected override ExecuteWorker<T> TakeWorker()
+        {
+            return _workers.Pop();
+        }
+
+        /// <summary>
+        /// Gets all workers.
+        /// </summary>
+        /// <returns></returns>
+        protected override IEnumerable<ExecuteWorker<T>> GetWorkers()
+        {
+            return _workers.ToArray();
+        }
+
+        /// <summary>
+        /// Clear all workers which not stated.
+        /// </summary>
+        protected override void CancelWorkers()
+        {
+            _workers.Clear();
+        }
+    }
+}

+ 6 - 6
WingServerCommon.csproj

@@ -4,12 +4,12 @@
     <TargetFramework>net6.0</TargetFramework>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-    <Version>1.0.0.19</Version>
-    <AssemblyVersion>1.0.0.19</AssemblyVersion>
-    <FileVersion>1.0.0.19</FileVersion>
-    <Version>1.0.0.19</Version>
-    <AssemblyVersion>1.0.0.19</AssemblyVersion>
-    <FileVersion>1.0.0.19</FileVersion>
+    <Version>1.0.0.20</Version>
+    <AssemblyVersion>1.0.0.20</AssemblyVersion>
+    <FileVersion>1.0.0.20</FileVersion>
+    <Version>1.0.0.20</Version>
+    <AssemblyVersion>1.0.0.20</AssemblyVersion>
+    <FileVersion>1.0.0.20</FileVersion>
   </PropertyGroup>
  <ItemGroup>
  <PackageReference Include="JsonRpcLite" Version="*" />