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

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
}
}