using System; using System.Collections.Generic; using System.Reflection; using System.Text; using System.Threading; namespace Apewer { /// Cron 特性,默认间隔为 60000 毫秒。 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public sealed class CronAttribute : Attribute { internal const int DefaultInterval = 60000; private int _interval; /// 两次 Cron 执行的间隔毫秒数。 public int Interval { get { return _interval; } } /// 创建 Cron 特性,可指定两次 Cron 执行的间隔毫秒数。 public CronAttribute(int interval = DefaultInterval) { _interval = interval; } #region Payload // 传入。 Type _type = null; Logger _logger = null; // 实时。 Thread _thread = null; bool _alive = false; void Run() { _alive = true; _thread = new Thread(Payload); _thread.IsBackground = false; _thread.Start(); } void Payload() { var moment = 500; var delay = 0; var sender = $"Cron-{_type.Name}"; while (true) { if (_break) break; if (delay <= 0) { delay = _interval; _logger.Text(sender, "Beginning"); try { var instance = Activator.CreateInstance(_type); RuntimeUtility.Dispose(instance); _logger.Text(sender, "Ended"); } catch (Exception ex) { _logger.Exception(sender, ex); } } else { Thread.Sleep(moment); delay = delay - moment; } } _alive = false; } #endregion #region CronInvoker static object _start = new object(); static CronAttribute[] _crons = null; static bool _break = false; static CronAttribute[] Init(IEnumerable assemblies = null, Logger logger = null) { var attributes = new List(); var added = new List(); if (assemblies == null) assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblies) { var types = assembly.GetTypes(); foreach (var type in types) { var attribute = RuntimeUtility.GetAttribute(type); if (attribute == null) continue; if (added.Contains(type.FullName)) continue; if (!RuntimeUtility.CanNew(type)) continue; attribute._type = type; attribute._logger = logger; attributes.Add(attribute); } } return attributes.ToArray(); } /// 开始 Cron 调用(阻塞当前线程)。 /// /// 参数
/// - assemblies: 包含 Cron 的程序集,不指定此参数时将在 AppDomain 中搜索;
/// - logger: 日志记录程序,不指定此参数时将使用 Logger.Default。
///
public static void Start(IEnumerable assemblies = null, Logger logger = null) { if (logger == null) logger = Logger.Default; lock (_start) { // 初始化。 _crons = Init(assemblies, logger); if (_crons.Length < 1) { logger.Error(nameof(CronAttribute), "没有找到带有 Cron 特性的类型。"); return; } // 启动线程。 Console.CancelKeyPress += (s, e) => { _break = true; e.Cancel = true; }; logger.Text(nameof(CronAttribute), $"启动 {_crons.Length} 个 Cron 线程。"); foreach (var cron in _crons) cron.Run(); // 监视退出状态。 while (true) { Thread.Sleep(300); var alive = 0; for (var i = 0; i < _crons.Length; i++) if (_crons[i]._alive) alive += 1; if (alive < 1) break; } logger.Text(nameof(CronAttribute), "所有 Cron 已结束。"); } } /// 打断 Cron 循环,不打断正在执行的 Cron。 public static void Break() { _break = true; } #endregion } }