| 
						
						
						
					 | 
				
				 | 
				
					@ -1,5 +1,6 @@ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using System; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using System.Collections.Generic; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using System.ComponentModel.Design; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using System.Reflection; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using System.Text; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using System.Threading; | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -8,10 +9,12 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					{ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    /// <summary>Cron 特性,默认间隔为 60 秒。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)] | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    public sealed class CronAttribute : Attribute, IToJson | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #region attribute
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private int _mode = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private int _seconds = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private CronCycle _cycle = CronCycle.Once; | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -51,7 +54,23 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return json; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #region Payload
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary></summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public override string ToString() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (_type != null) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (_mode == 1) return $"Type = {_type.FullName}, Seconds = {_seconds}"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (_mode == 2) return $"Type = {_type.FullName}, Cycle = {_cycle}, Seconds = {_seconds}"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return base.ToString(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #endregion
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #region payload
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>执行 Cron 的类。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public Type Type { get => _type; } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        // 传入。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        Type _type = null; | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -61,13 +80,25 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        // 实时。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        Thread _thread = null; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        bool _alive = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        bool _break = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>运行当前 Cron。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        void Run() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            _alive = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            _thread = new Thread(Payload); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            _thread.IsBackground = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            _thread.Start(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (_alive) return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (_type == null) return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            _break = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            UsePool(pool => | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (pool.ContainsKey(_type)) return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                pool.Add(_type, this); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                _alive = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                _thread = new Thread(Payload); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                _thread.IsBackground = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                _thread.Start(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        // 当前进程睡眠。
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -83,11 +114,11 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var next = DateTime.MinValue; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                while (true) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (_break) break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (_break || _break_all) break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (_now < next) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        Sleep(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        if (_break) break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        if (_break || _break_all) break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        continue; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -102,9 +133,9 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var next = DateTime.Now.AddSeconds(_seconds); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                while (_now < next) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (_break) break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (_break || _break_all) break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    Sleep(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (_break) break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (_break || _break_all) break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                Invoke(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -134,11 +165,11 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                // 启动循环。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                while (true) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (_break) break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (_break || _break_all) break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (_now < next) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        Sleep(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        if (_break) break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        if (_break || _break_all) break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        continue; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -164,7 +195,13 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            _alive = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            UsePool(pool => | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (pool.ContainsKey(_type)) pool.Remove(_type); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                _break = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                _alive = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        void Invoke() | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -188,13 +225,52 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #endregion
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #region CronInvoker
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #region pool
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static Dictionary<Type, CronAttribute> _pool = new Dictionary<Type, CronAttribute>(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static void UsePool(Action<Dictionary<Type, CronAttribute>> callback) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (callback == null) throw new ArgumentNullException(nameof(callback)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            lock (_pool) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                callback.Invoke(_pool); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static object _start = new object(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static CronAttribute[] _crons = null; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static bool _break = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static T UsePool<T>(Func<Dictionary<Type, CronAttribute>, T> callback) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (callback == null) throw new ArgumentNullException(nameof(callback)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            lock (_pool) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return callback.Invoke(_pool); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #endregion
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #region invoker
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static bool _break_all = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static DateTime _now; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static int _crons_alive = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>获取状态,指示打断 Cron 循环。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static bool Breaking { get => _break_all; } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>正在运行的 Cron 数量。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static int AliveCount { get => CountAlive(UsePool(pool => pool.Values)); } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>获取正在运行的 Cron 数量。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <returns></returns>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static int CountAlive(IEnumerable<CronAttribute> crons) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var alive = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            foreach (var cron in crons) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (cron._alive) alive += 1; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return alive; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static CronAttribute[] Init(IEnumerable<Assembly> assemblies, Logger logger, bool logEvent) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -226,6 +302,14 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return array; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>启动指定的 Cron。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <exception cref="ArgumentNullException"></exception>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Start(CronAttribute cron) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (cron == null) throw new ArgumentNullException(nameof(cron)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            cron.Run(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>开始 Cron 调用(阻塞当前线程)。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <param name="assemblies">包含 Cron 的程序集,不指定此参数时将在 AppDomain 中搜索。</param>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <param name="logger">日志记录程序,不指定此参数时将使用 Logger.Default。</param>
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -239,71 +323,122 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Start(IEnumerable<Assembly> assemblies = null, Logger logger = null, bool logEvent = true) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (logger == null) logger = Logger.Default; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            lock (_start) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            // 设置控制台事件。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            Console.CancelKeyPress += (s, e) => | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                // 初始化。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                _now = DateTime.Now; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                _crons = Init(assemblies, logger, logEvent); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (_crons.Length < 1) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    logger.Error(nameof(CronAttribute), "没有找到带有 Cron 特性的类型。"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                _break_all = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                e.Cancel = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            // 初始化。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            _now = DateTime.Now; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var crons = Init(assemblies, logger, logEvent); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (crons.Length > 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                logger.Text(nameof(CronAttribute), "Crons started。"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                // 启动线程。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                _crons_alive = _crons.Length; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                Console.CancelKeyPress += (s, e) => | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    _break = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    e.Cancel = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                logger.Text(nameof(CronAttribute), $"启动 {_crons.Length} 个 Cron 线程。"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                foreach (var cron in _crons) cron.Run(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                // 启动 Cron。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                foreach (var cron in crons) Start(cron); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                // 监视退出状态。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                // 等待 Cron 退出。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                while (true) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    Thread.Sleep(100); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    _now = DateTime.Now; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    var alive = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    for (var i = 0; i < _crons.Length; i++) if (_crons[i]._alive) alive += 1; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (alive < 1) break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    _crons_alive = alive; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (AliveCount < 1) break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                logger.Text(nameof(CronAttribute), "所有 Cron 已结束。"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            logger.Text(nameof(CronAttribute), "Crons ended。"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>打断正在执行的 Cron。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Abort() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>打断指定的 Cron。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <exception cref="ArgumentNullException" />
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Abort(Type type) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var crons = _crons; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (crons != null) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (type == null) throw new ArgumentNullException(nameof(type)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            UsePool(pool => | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                foreach (var cron in crons) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (pool.TryGetValue(type, out var cron)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (cron == null) continue; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    try { cron._thread.Abort(); } catch { } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                pool.Remove(type); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>打断指定的 Cron。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <exception cref="ArgumentNullException" />
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Abort(object instance) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (instance == null) throw new ArgumentNullException(nameof(instance)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (instance is Type type) Abort(type); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            else Abort(instance.GetType()); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>打断 Cron 循环,不打断正在执行的 Cron。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>打断所有 Cron。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Abort() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            UsePool(pool => | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                foreach (var item in pool) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    try | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        item.Value._thread.Abort(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        item.Value._alive = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        item.Value._break = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    catch { } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>打断 Cron 循环,不打断正在执行的 Job。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <exception cref="ArgumentNullException" />
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Break(Type type) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (type == null) throw new ArgumentNullException(nameof(type)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            UsePool(pool => | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (pool.TryGetValue(type, out var cron)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    cron._break = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>打断 Cron 循环,不打断正在执行的 Job。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <exception cref="ArgumentNullException" />
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Break(object instance) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (instance == null) throw new ArgumentNullException(nameof(instance)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (instance is Type type) Break(type); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            else Break(instance.GetType()); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>打断 Cron 循环,不打断正在执行的 Job。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Break() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            _break = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            _break_all = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>打断 Cron 循环并等待 Cron 执行结束。等待指定的时间后打断正在执行的 Cron。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>打断 Cron 循环并等待 Job 执行结束。等待指定的时间后打断正在执行的 Job。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <param name="timeout">强制打断前的等待毫秒数,指定为负数时将无限等待。</param>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Break(int timeout) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            _break = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            _break_all = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            const int interval = 100; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (timeout < 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                while (_crons_alive > 0) Thread.Sleep(interval); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                while (AliveCount > 0) Thread.Sleep(interval); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            else | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -311,7 +446,7 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (timeout > 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    var remains = timeout; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    while (remains > 0 && _crons_alive > 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    while (remains > 0 && AliveCount > 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        Thread.Sleep(interval); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        remains -= interval; | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -321,9 +456,6 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>获取状态,指示打断 Cron 循环。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static bool Breaking { get => _break; } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #endregion
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
				 | 
				
					
  |