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