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.

189 lines
5.5 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
  1. using Apewer;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Reflection;
  5. using System.Text;
  6. using System.Threading;
  7. namespace Apewer.Web
  8. {
  9. /// <summary>Cron 调度器。</summary>
  10. internal sealed class CronInvoker
  11. {
  12. #region Instance
  13. private List<Assembly> _assemblies = null;
  14. private List<CronInstance> _instances = null;
  15. private bool _break = false;
  16. private Logger _logger = null;
  17. /// <summary>获取或设置日志记录器。</summary>
  18. public Logger Logger { get { return _logger; } set { _logger = value; } }
  19. private void Log(object content) => _logger?.Text("Cron", content);
  20. /// <summary>加载程序集。</summary>
  21. public void Load(IEnumerable<Assembly> assemblies)
  22. {
  23. Log("开始加载程序集。");
  24. if (_assemblies == null) _assemblies = new List<Assembly>();
  25. if (_assemblies.Count > 0)
  26. {
  27. Log("程序集列表为空。");
  28. return;
  29. }
  30. if (assemblies == null)
  31. {
  32. _assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies());
  33. }
  34. else
  35. {
  36. foreach (var assembly in assemblies)
  37. {
  38. if (assembly == null) continue;
  39. if (_assemblies.Contains(assembly)) continue;
  40. _assemblies.Add(assembly);
  41. }
  42. }
  43. var count = _assemblies.Count.ToString();
  44. Log($"已加载 {count} 个程序集。");
  45. }
  46. /// <summary>通知打断循环,所有 Cron 执行结束后退出。</summary>
  47. public void Break() => _break = true;
  48. /// <summary>开始 Cron 调用。</summary>
  49. public void Start()
  50. {
  51. if (_instances != null) return;
  52. _instances = GetInstances();
  53. var count = _assemblies.Count.ToString();
  54. Log($"检查到 {count} 个 Cron 类型。");
  55. foreach (var i in _instances) Log(i.Type.FullName);
  56. while (true)
  57. {
  58. // CronLog.Write("Tick");
  59. var alive = 0;
  60. foreach (var i in _instances)
  61. {
  62. // 跳出。
  63. if (i.Alive) alive++;
  64. if (_break)
  65. {
  66. i.Break();
  67. break;
  68. }
  69. // 当前线程正在活动。
  70. if (i.Alive)
  71. {
  72. i._latest = true;
  73. continue;
  74. }
  75. // 记录 Cron 结束时间,根据结束时间判断再次启动 Cron。
  76. if (i.Latest)
  77. {
  78. Log($"{i.Type.FullName} Ended");
  79. i._ended = new Class<DateTime>(DateTime.Now);
  80. i._latest = false;
  81. }
  82. if (i.Ended == null)
  83. {
  84. Log($"{i.Type.FullName} Beginning");
  85. i.Start();
  86. i._latest = true;
  87. }
  88. else
  89. {
  90. var span = DateTime.Now - i.Ended.Value;
  91. if (span.TotalMilliseconds >= Convert.ToDouble(i.Interval))
  92. {
  93. Log($"{i.Type.FullName} Beginning");
  94. i.Start();
  95. i._latest = true;
  96. }
  97. }
  98. }
  99. if (_break && alive < 1)
  100. {
  101. break;
  102. }
  103. Thread.Sleep(500);
  104. GC.Collect();
  105. }
  106. Log("循环结束,即将退出。");
  107. }
  108. private List<CronInstance> GetInstances()
  109. {
  110. var list = new List<CronInstance>();
  111. var types = GetTypes();
  112. foreach (var type in types)
  113. {
  114. var attribute = RuntimeUtility.GetAttribute<CronAttribute>(type, false);
  115. if (attribute == null) continue;
  116. var instance = new CronInstance();
  117. instance._invoker = this;
  118. instance._attribute = attribute;
  119. instance._type = type;
  120. instance._logger = Logger;
  121. list.Add(instance);
  122. }
  123. return list;
  124. }
  125. private List<Type> GetTypes()
  126. {
  127. var list = new List<Type>();
  128. var assemblies = _assemblies;
  129. foreach (var assembly in assemblies)
  130. {
  131. var types = RuntimeUtility.GetTypes(assembly);
  132. foreach (var type in types)
  133. {
  134. if (!type.IsPublic) continue;
  135. if (type.IsAbstract) continue;
  136. if (!RuntimeUtility.CanNew(type)) continue;
  137. list.Add(type);
  138. }
  139. }
  140. return list;
  141. }
  142. #endregion
  143. #region Static
  144. // 在当前线程开始 Cron 调用 。
  145. public static CronInvoker Start(IEnumerable<Assembly> assemblies = null, Logger logger = null)
  146. {
  147. var instance = new CronInvoker();
  148. instance.Logger = logger;
  149. instance.Load(assemblies ?? AppDomain.CurrentDomain.GetAssemblies());
  150. instance.Start();
  151. return instance;
  152. }
  153. #endregion
  154. }
  155. }