You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
4.9 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.Text;
  5. using System.Threading;
  6. namespace Apewer
  7. {
  8. /// <summary>Cron 特性,默认间隔为 60000 毫秒。</summary>
  9. [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
  10. public sealed class CronAttribute : Attribute
  11. {
  12. internal const int DefaultInterval = 60000;
  13. private int _interval;
  14. /// <summary>两次 Cron 执行的间隔毫秒数。</summary>
  15. public int Interval { get { return _interval; } }
  16. /// <summary>创建 Cron 特性,可指定两次 Cron 执行的间隔毫秒数。</summary>
  17. public CronAttribute(int interval = DefaultInterval) { _interval = interval; }
  18. #region Payload
  19. // 传入。
  20. Type _type = null;
  21. Logger _logger = null;
  22. // 实时。
  23. Thread _thread = null;
  24. bool _alive = false;
  25. void Run()
  26. {
  27. _alive = true;
  28. _thread = new Thread(Payload);
  29. _thread.IsBackground = false;
  30. _thread.Start();
  31. }
  32. void Payload()
  33. {
  34. var moment = 500;
  35. var delay = 0;
  36. var sender = $"Cron-{_type.Name}";
  37. while (true)
  38. {
  39. if (_break) break;
  40. if (delay <= 0)
  41. {
  42. delay = _interval;
  43. _logger.Text(sender, "Beginning");
  44. try
  45. {
  46. var instance = Activator.CreateInstance(_type);
  47. RuntimeUtility.Dispose(instance);
  48. _logger.Text(sender, "Ended");
  49. }
  50. catch (Exception ex)
  51. {
  52. _logger.Exception(sender, ex);
  53. }
  54. }
  55. else
  56. {
  57. Thread.Sleep(moment);
  58. delay = delay - moment;
  59. }
  60. }
  61. _alive = false;
  62. }
  63. #endregion
  64. #region CronInvoker
  65. static object _start = new object();
  66. static CronAttribute[] _crons = null;
  67. static bool _break = false;
  68. static CronAttribute[] Init(IEnumerable<Assembly> assemblies = null, Logger logger = null)
  69. {
  70. var attributes = new List<CronAttribute>();
  71. var added = new List<string>();
  72. if (assemblies == null) assemblies = AppDomain.CurrentDomain.GetAssemblies();
  73. foreach (var assembly in assemblies)
  74. {
  75. var types = assembly.GetTypes();
  76. foreach (var type in types)
  77. {
  78. var attribute = RuntimeUtility.GetAttribute<CronAttribute>(type);
  79. if (attribute == null) continue;
  80. if (added.Contains(type.FullName)) continue;
  81. if (!RuntimeUtility.CanNew(type)) continue;
  82. attribute._type = type;
  83. attribute._logger = logger;
  84. attributes.Add(attribute);
  85. }
  86. }
  87. return attributes.ToArray();
  88. }
  89. /// <summary>开始 Cron 调用(阻塞当前线程)。</summary>
  90. /// <remarks>
  91. /// 参数<br />
  92. /// - assemblies: 包含 Cron 的程序集,不指定此参数时将在 AppDomain 中搜索;<br />
  93. /// - logger: 日志记录程序,不指定此参数时将使用 Logger.Default。<br />
  94. /// </remarks>
  95. public static void Start(IEnumerable<Assembly> assemblies = null, Logger logger = null)
  96. {
  97. if (logger == null) logger = Logger.Default;
  98. lock (_start)
  99. {
  100. // 初始化。
  101. _crons = Init(assemblies, logger);
  102. if (_crons.Length < 1)
  103. {
  104. logger.Error(nameof(CronAttribute), "没有找到带有 Cron 特性的类型。");
  105. return;
  106. }
  107. // 启动线程。
  108. Console.CancelKeyPress += (s, e) =>
  109. {
  110. _break = true;
  111. e.Cancel = true;
  112. };
  113. logger.Text(nameof(CronAttribute), $"启动 {_crons.Length} 个 Cron 线程。");
  114. foreach (var cron in _crons) cron.Run();
  115. // 监视退出状态。
  116. while (true)
  117. {
  118. Thread.Sleep(300);
  119. var alive = 0;
  120. for (var i = 0; i < _crons.Length; i++) if (_crons[i]._alive) alive += 1;
  121. if (alive < 1) break;
  122. }
  123. logger.Text(nameof(CronAttribute), "所有 Cron 已结束。");
  124. }
  125. }
  126. /// <summary>打断 Cron 循环,不打断正在执行的 Cron。</summary>
  127. public static void Break()
  128. {
  129. _break = true;
  130. }
  131. #endregion
  132. }
  133. }