namespace Admin.NET.Core.Service;
///
/// 定时任务服务
///
[ApiDescriptionSettings(Name = "定时任务", Order = 188)]
public class SysTimerService : IDynamicApiController, ITransient
{
private readonly SqlSugarRepository _sysTimerRep;
private readonly ISysCacheService _sysCacheService;
public SysTimerService(SqlSugarRepository sysTimerRep,
ISysCacheService sysCacheService)
{
_sysTimerRep = sysTimerRep;
_sysCacheService = sysCacheService;
}
///
/// 获取任务分页列表
///
///
///
[HttpGet("/sysTimer/page")]
public async Task> GetTimerPage([FromQuery] PageTimerInput input)
{
var workers = SpareTime.GetWorkers().ToList();
var timers = await _sysTimerRep.AsQueryable()
.WhereIF(!string.IsNullOrWhiteSpace(input.TimerName), u => u.TimerName.Contains(input.TimerName))
.Select()
.ToPagedListAsync(input.Page, input.PageSize);
timers.Items.ToList().ForEach(u =>
{
var timer = workers.FirstOrDefault(m => m.WorkerName == u.TimerName);
if (timer != null)
{
u.Status = timer.Status;
u.Tally = timer.Tally;
u.Exception = JSON.Serialize(timer.Exception);
}
});
return timers;
}
///
/// 增加任务
///
///
///
[HttpPost("/sysTimer/add")]
public async Task AddTimer(AddTimerInput input)
{
var isExist = await _sysTimerRep.IsAnyAsync(u => u.TimerName == input.TimerName);
if (isExist) throw Oops.Oh(ErrorCodeEnum.D1100);
var timer = input.Adapt();
await _sysTimerRep.InsertAsync(timer);
CreateTimer(timer); // 添加到任务调度里
}
///
/// 删除任务
///
///
///
[HttpPost("/sysTimer/delete")]
public async Task DeleteTimer(DeleteTimerInput input)
{
var timer = await _sysTimerRep.GetFirstAsync(u => u.Id == input.Id);
if (timer == null) throw Oops.Oh(ErrorCodeEnum.D1101);
await _sysTimerRep.DeleteAsync(timer);
SpareTime.Cancel(timer.TimerName); // 从调度器里取消
}
///
/// 更新任务
///
///
///
[HttpPost("/sysTimer/update")]
public async Task UpdateTimber(UpdateTimerInput input)
{
var isExist = await _sysTimerRep.IsAnyAsync(u => u.TimerName == input.TimerName && u.Id != input.Id);
if (isExist) throw Oops.Oh(ErrorCodeEnum.D1100);
// 先从调度器里取消
var oldTimer = await _sysTimerRep.GetFirstAsync(u => u.Id == input.Id);
SpareTime.Cancel(oldTimer.TimerName);
var timer = input.Adapt();
await _sysTimerRep.AsUpdateable(timer).IgnoreColumns(true).ExecuteCommandAsync();
CreateTimer(timer); // 再添加到任务调度里
}
///
/// 设置任务状态
///
///
///
[HttpPost("/sysTimer/setStatus")]
public async void SetStatusTimer(SetTimerStatusInput input)
{
if (input.Status == SpareTimeStatus.Stopped)
SpareTime.Stop(input.TimerName);
else if (input.Status == SpareTimeStatus.Running)
{
var spareTime = SpareTime.GetWorkers().ToList().Find(u => u.WorkerName == input.TimerName);
if (spareTime == null)
{
var timer = await _sysTimerRep.GetFirstAsync(u => u.TimerName == input.TimerName);
CreateTimer(timer);
}
SpareTime.Start(input.TimerName); // 若StartNow=flase则不会启动任务
}
}
///
/// 创建定时任务
///
///
private async void CreateTimer(SysTimer input)
{
Action action = null;
switch (input.RequestType)
{
case RequestTypeEnum.Run: // 创建本地方法委托
{
var taskMethod = GetTimerMethodList()?.Result.FirstOrDefault(m => m.RequestUrl == input.RequestUrl);
if (taskMethod == null) break;
var typeInstance = Activator.CreateInstance(taskMethod.DeclaringType);
action = (Action)Delegate.CreateDelegate(typeof(Action), typeInstance, taskMethod.MethodName);
break;
}
default: // 创建网络任务委托
{
action = async (_, _) =>
{
var requestUrl = input.RequestUrl.Trim();
requestUrl = requestUrl?.IndexOf("http") == 0 ? requestUrl : "http://" + requestUrl; // 默认http协议
var requestParameters = input.RequestPara;
var headersString = input.Headers;
var headers = string.IsNullOrEmpty(headersString)
? null : JSON.Deserialize>(headersString);
switch (input.RequestType)
{
case RequestTypeEnum.Get:
await requestUrl.SetHeaders(headers).GetAsync();
break;
case RequestTypeEnum.Post:
await requestUrl.SetHeaders(headers).SetQueries(requestParameters).PostAsync();
break;
case RequestTypeEnum.Put:
await requestUrl.SetHeaders(headers).SetQueries(requestParameters).PutAsync();
break;
case RequestTypeEnum.Delete:
await requestUrl.SetHeaders(headers).DeleteAsync();
break;
}
};
break;
}
}
if (action == null) return;
// 缓存任务配置参数供任务运行时读取
if (input.RequestType == RequestTypeEnum.Run)
{
var timerParaName = $"{input.TimerName}_para";
var timerPara = await _sysCacheService.ExistsAsync(timerParaName);
var requestPara = string.IsNullOrEmpty(input.RequestPara);
// 若没有任务配置但存在缓存则删除
if (requestPara && timerPara)
await _sysCacheService.RemoveAsync(timerParaName);
else if (!requestPara)
await _sysCacheService.SetAsync(timerParaName, JSON.Deserialize>(input.RequestPara));
}
// 创建定时任务
switch (input.TimerType)
{
case SpareTimeTypes.Interval:
if (input.DoOnce)
SpareTime.DoOnce((int)input.Interval * 1000, action, input.TimerName, input.Remark, input.StartNow, executeType: input.ExecuteType);
else
SpareTime.Do((int)input.Interval * 1000, action, input.TimerName, input.Remark, input.StartNow, executeType: input.ExecuteType);
break;
case SpareTimeTypes.Cron:
SpareTime.Do(input.Cron, action, input.TimerName, input.Remark, input.StartNow, executeType: input.ExecuteType);
break;
}
}
///
/// 获取所有定时任务方法列表(贴spareTime特性)
///
///
private async Task> GetTimerMethodList()
{
// 有缓存就返回缓存
var timerMethodList = await _sysCacheService.GetAsync>(CacheConst.KeyTimer);
if (timerMethodList != null) return timerMethodList;
timerMethodList = App.EffectiveTypes
.Where(u => u.IsClass && !u.IsInterface && !u.IsAbstract && typeof(ISpareTimeWorker).IsAssignableFrom(u))
.SelectMany(u => u.GetMethods(BindingFlags.Public | BindingFlags.Instance)
.Where(m => m.IsDefined(typeof(SpareTimeAttribute), false) &&
m.GetParameters().Length == 2 &&
m.GetParameters()[0].ParameterType == typeof(SpareTimer) &&
m.GetParameters()[1].ParameterType == typeof(long) && m.ReturnType == typeof(void))
.Select(m =>
{
// 默认获取第一条任务特性
var spareTimeAttribute = m.GetCustomAttribute();
return new TimerMethod
{
TimerName = spareTimeAttribute.WorkerName,
RequestUrl = $"{m.DeclaringType.Name}/{m.Name}",
Cron = spareTimeAttribute.CronExpression,
DoOnce = spareTimeAttribute.DoOnce,
ExecuteType = spareTimeAttribute.ExecuteType,
Interval = (int)spareTimeAttribute.Interval / 1000,
StartNow = spareTimeAttribute.StartNow,
RequestType = RequestTypeEnum.Run,
Remark = spareTimeAttribute.Description,
TimerType = string.IsNullOrEmpty(spareTimeAttribute.CronExpression) ? SpareTimeTypes.Interval : SpareTimeTypes.Cron,
MethodName = m.Name,
DeclaringType = m.DeclaringType
};
}));
await _sysCacheService.SetAsync(CacheConst.KeyTimer, timerMethodList);
return timerMethodList;
}
///
/// 启动自启动任务
///
[NonAction]
public async void StartTimer()
{
var timerList = await _sysTimerRep.GetListAsync(t => t.StartNow);
timerList.ForEach(CreateTimer);
}
}