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