11 changed files with 124 additions and 331 deletions
@ -1,95 +0,0 @@ |
|||||
using Apewer; |
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Text; |
|
||||
using System.Threading; |
|
||||
|
|
||||
namespace Apewer.Web |
|
||||
{ |
|
||||
|
|
||||
internal sealed class CronInstance |
|
||||
{ |
|
||||
|
|
||||
internal bool _latest = false; |
|
||||
internal Type _type = null; |
|
||||
internal Logger _logger = null; |
|
||||
internal Class<DateTime> _ended = null; |
|
||||
internal CronAttribute _attribute = null; |
|
||||
internal CronInvoker _invoker = null; |
|
||||
|
|
||||
private Thread _thread = null; |
|
||||
private bool _break = false; |
|
||||
|
|
||||
#region properties
|
|
||||
|
|
||||
// 当前线程正在运行。
|
|
||||
public bool Alive { get => GetAlive(); } |
|
||||
|
|
||||
// 再次启动 Cron 的时间间隔。
|
|
||||
public int Interval { get => GetInterval(); } |
|
||||
|
|
||||
// 最后一次检查的 Alive 值。
|
|
||||
public bool Latest { get => _latest; } |
|
||||
|
|
||||
// Cron 类型。
|
|
||||
public Type Type { get => _type; } |
|
||||
|
|
||||
public CronAttribute Attribute { get => _attribute; } |
|
||||
|
|
||||
public Class<DateTime> Ended { get => _ended; } |
|
||||
|
|
||||
#endregion
|
|
||||
|
|
||||
public CronInstance() |
|
||||
{ |
|
||||
_thread = new Thread(Listen); |
|
||||
_thread.IsBackground = true; |
|
||||
} |
|
||||
|
|
||||
/// <summary>打断循环。</summary>
|
|
||||
public void Break() => _break = true; |
|
||||
|
|
||||
/// <summary>启动线程执行任务。</summary>
|
|
||||
public void Start() |
|
||||
{ |
|
||||
if (Alive) return; |
|
||||
_thread = new Thread(Listen); |
|
||||
_thread.IsBackground = true; |
|
||||
_thread.Start(); |
|
||||
} |
|
||||
|
|
||||
int GetInterval() |
|
||||
{ |
|
||||
if (_attribute == null) _attribute = new CronAttribute(); |
|
||||
return _attribute.Interval; |
|
||||
} |
|
||||
|
|
||||
bool GetAlive() |
|
||||
{ |
|
||||
if (_thread == null) return false; |
|
||||
if (_thread.IsAlive != true) return false; |
|
||||
if (_thread.ThreadState != ThreadState.Running) return false; |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
void Listen() |
|
||||
{ |
|
||||
if (Type == null) return; |
|
||||
var instance = null as object; |
|
||||
try |
|
||||
{ |
|
||||
instance = Activator.CreateInstance(Type); |
|
||||
} |
|
||||
catch (Exception exception) |
|
||||
{ |
|
||||
Log(Type.FullName, exception.GetType().FullName, exception.Message); |
|
||||
} |
|
||||
RuntimeUtility.Dispose(instance); |
|
||||
_thread = null; |
|
||||
} |
|
||||
|
|
||||
void Log(params object[] content) => _logger.Text(Type.FullName, content); |
|
||||
|
|
||||
} |
|
||||
|
|
||||
} |
|
@ -1,189 +0,0 @@ |
|||||
using Apewer; |
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Reflection; |
|
||||
using System.Text; |
|
||||
using System.Threading; |
|
||||
|
|
||||
namespace Apewer.Web |
|
||||
{ |
|
||||
|
|
||||
/// <summary>Cron 调度器。</summary>
|
|
||||
internal sealed class CronInvoker |
|
||||
{ |
|
||||
|
|
||||
#region Instance
|
|
||||
|
|
||||
private List<Assembly> _assemblies = null; |
|
||||
private List<CronInstance> _instances = null; |
|
||||
private bool _break = false; |
|
||||
private Logger _logger = null; |
|
||||
|
|
||||
/// <summary>获取或设置日志记录器。</summary>
|
|
||||
public Logger Logger { get { return _logger; } set { _logger = value; } } |
|
||||
|
|
||||
private void Log(object content) => _logger?.Text("Cron", content); |
|
||||
|
|
||||
/// <summary>加载程序集。</summary>
|
|
||||
public void Load(IEnumerable<Assembly> assemblies) |
|
||||
{ |
|
||||
Log("开始加载程序集。"); |
|
||||
if (_assemblies == null) _assemblies = new List<Assembly>(); |
|
||||
if (_assemblies.Count > 0) |
|
||||
{ |
|
||||
Log("程序集列表为空。"); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
if (assemblies == null) |
|
||||
{ |
|
||||
_assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies()); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
foreach (var assembly in assemblies) |
|
||||
{ |
|
||||
if (assembly == null) continue; |
|
||||
if (_assemblies.Contains(assembly)) continue; |
|
||||
_assemblies.Add(assembly); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
var count = _assemblies.Count.ToString(); |
|
||||
Log($"已加载 {count} 个程序集。"); |
|
||||
} |
|
||||
|
|
||||
/// <summary>通知打断循环,所有 Cron 执行结束后退出。</summary>
|
|
||||
public void Break() => _break = true; |
|
||||
|
|
||||
/// <summary>开始 Cron 调用。</summary>
|
|
||||
public void Start() |
|
||||
{ |
|
||||
if (_instances != null) return; |
|
||||
_instances = GetInstances(); |
|
||||
|
|
||||
var count = _assemblies.Count.ToString(); |
|
||||
Log($"检查到 {count} 个 Cron 类型。"); |
|
||||
|
|
||||
foreach (var i in _instances) Log(i.Type.FullName); |
|
||||
while (true) |
|
||||
{ |
|
||||
// CronLog.Write("Tick");
|
|
||||
var alive = 0; |
|
||||
foreach (var i in _instances) |
|
||||
{ |
|
||||
// 跳出。
|
|
||||
if (i.Alive) alive++; |
|
||||
if (_break) |
|
||||
{ |
|
||||
i.Break(); |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
// 当前线程正在活动。
|
|
||||
if (i.Alive) |
|
||||
{ |
|
||||
i._latest = true; |
|
||||
continue; |
|
||||
} |
|
||||
|
|
||||
// 记录 Cron 结束时间,根据结束时间判断再次启动 Cron。
|
|
||||
if (i.Latest) |
|
||||
{ |
|
||||
Log($"{i.Type.FullName} Ended"); |
|
||||
i._ended = new Class<DateTime>(DateTime.Now); |
|
||||
i._latest = false; |
|
||||
} |
|
||||
|
|
||||
if (i.Ended == null) |
|
||||
{ |
|
||||
Log($"{i.Type.FullName} Beginning"); |
|
||||
i.Start(); |
|
||||
i._latest = true; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
var span = DateTime.Now - i.Ended.Value; |
|
||||
if (span.TotalMilliseconds >= Convert.ToDouble(i.Interval)) |
|
||||
{ |
|
||||
Log($"{i.Type.FullName} Beginning"); |
|
||||
i.Start(); |
|
||||
i._latest = true; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (_break && alive < 1) |
|
||||
{ |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
Thread.Sleep(500); |
|
||||
GC.Collect(); |
|
||||
} |
|
||||
|
|
||||
Log("循环结束,即将退出。"); |
|
||||
} |
|
||||
|
|
||||
private List<CronInstance> GetInstances() |
|
||||
{ |
|
||||
var list = new List<CronInstance>(); |
|
||||
|
|
||||
var types = GetTypes(); |
|
||||
foreach (var type in types) |
|
||||
{ |
|
||||
var attribute = RuntimeUtility.GetAttribute<CronAttribute>(type, false); |
|
||||
if (attribute == null) continue; |
|
||||
|
|
||||
var instance = new CronInstance(); |
|
||||
instance._invoker = this; |
|
||||
instance._attribute = attribute; |
|
||||
instance._type = type; |
|
||||
instance._logger = Logger; |
|
||||
|
|
||||
list.Add(instance); |
|
||||
} |
|
||||
|
|
||||
return list; |
|
||||
} |
|
||||
|
|
||||
private List<Type> GetTypes() |
|
||||
{ |
|
||||
var list = new List<Type>(); |
|
||||
|
|
||||
var assemblies = _assemblies; |
|
||||
foreach (var assembly in assemblies) |
|
||||
{ |
|
||||
var types = RuntimeUtility.GetTypes(assembly); |
|
||||
foreach (var type in types) |
|
||||
{ |
|
||||
if (!type.IsPublic) continue; |
|
||||
if (type.IsAbstract) continue; |
|
||||
if (!RuntimeUtility.CanNew(type)) continue; |
|
||||
|
|
||||
list.Add(type); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return list; |
|
||||
} |
|
||||
|
|
||||
#endregion
|
|
||||
|
|
||||
#region Static
|
|
||||
|
|
||||
// 在当前线程开始 Cron 调用 。
|
|
||||
public static CronInvoker Start(IEnumerable<Assembly> assemblies = null, Logger logger = null) |
|
||||
{ |
|
||||
var instance = new CronInvoker(); |
|
||||
instance.Logger = logger; |
|
||||
instance.Load(assemblies ?? AppDomain.CurrentDomain.GetAssemblies()); |
|
||||
instance.Start(); |
|
||||
return instance; |
|
||||
} |
|
||||
|
|
||||
#endregion
|
|
||||
|
|
||||
} |
|
||||
|
|
||||
} |
|
Loading…
Reference in new issue