using NCC; using NCC.Common.Core.Manager; using NCC.Common.Enum; using NCC.Common.Extension; using NCC.Common.Filter; using NCC.Dependency; using NCC.DynamicApiController; using NCC.FriendlyException; using NCC.JsonSerialization; using NCC.LinqBuilder; using NCC.RemoteRequest.Extensions; using NCC.System.Interfaces.System; using NCC.TaskScheduler; using NCC.TaskScheduler.Entitys.Dto.TaskScheduler; using NCC.TaskScheduler.Entitys.Entity; using NCC.TaskScheduler.Entitys.Model; using NCC.TaskScheduler.Interfaces.TaskScheduler; using Mapster; using Microsoft.AspNetCore.Mvc; using SqlSugar; using SqlSugar.IOC; using System; using System.Collections.Generic; using System.Threading.Tasks; namespace NCC.TaskScheduler.TaskScheduler { ///     /// 定时任务     /// 版 本:V1.20.15     /// 版 权:Wesley(https://www.NCCsoft.com)     /// 作 者:NCC开发平台组     /// 日 期:2022-03-16     /// [ApiDescriptionSettings(Tag = "TaskScheduler", Name = "scheduletask", Order = 220)] [Route("api/[controller]")] public class TimeTaskService : ITimeTaskService, IDynamicApiController, ITransient { private readonly ISqlSugarRepository _timeTaskRepository; private readonly ISqlSugarRepository _timeTaskLogRepository; private readonly IDbLinkService _dblikServer; private readonly IDataBaseService _dataBaseService; private readonly SqlSugarScope db; private readonly IUserManager _userManager; private readonly ISpareTimeListener _spareTimeListener; /// /// 初始化一个类型的新实例 /// public TimeTaskService(ISqlSugarRepository timeTaskRepository, ISqlSugarRepository timeTaskLogRepository, IUserManager userManager, IDbLinkService dblikServer, IDataBaseService dataBaseService, ISpareTimeListener spareTimeListener) { _timeTaskRepository = timeTaskRepository; _timeTaskLogRepository = timeTaskLogRepository; db = timeTaskRepository.Context; _userManager = userManager; _dblikServer = dblikServer; _dataBaseService = dataBaseService; _spareTimeListener = spareTimeListener; } #region Get /// /// 列表 /// /// 请求参数 /// [HttpGet("")] public async Task GetList([FromQuery] PageInputBase input) { var queryWhere = LinqExpression.And().And(x => x.DeleteMark == null); if (!string.IsNullOrEmpty(input.keyword)) queryWhere = queryWhere.And(m => m.FullName.Contains(input.keyword) || m.EnCode.Contains(input.keyword)); var list = await _timeTaskRepository.Entities.Where(queryWhere).OrderBy(x => x.CreatorTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize); var pageList = new SqlSugarPagedList() { list = list.list.Adapt>(), pagination = list.pagination }; return PageResult.SqlSugarPageResult(pageList); } /// /// 列表(执行记录) /// /// 请求参数 /// 任务Id /// [HttpGet("{id}/TaskLog")] public async Task GetTaskLogList([FromQuery] TaskLogInput input, string id) { var whereLambda = LinqExpression.And().And(x => x.TaskId == id); if (input.runResult.IsNotEmptyOrNull()) { whereLambda = whereLambda.And(x => x.RunResult == input.runResult); } if (!input.startTime.IsNullOrEmpty() && !input.endTime.IsNullOrEmpty()) { var start = Ext.GetDateTime(input.startTime.ToString()); var end = Ext.GetDateTime(input.endTime.ToString()); start = new DateTime(start.Year, start.Month, start.Day, 0, 0, 0, 0); end = new DateTime(end.Year, end.Month, end.Day, 23, 59, 59, 999); whereLambda = whereLambda.And(x => SqlFunc.Between(x.RunTime, start, end)); } var list = await _timeTaskLogRepository.Entities.Where(whereLambda).OrderBy(x => x.RunTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize); var pageList = new SqlSugarPagedList() { list = list.list.Adapt>(), pagination = list.pagination }; return PageResult.SqlSugarPageResult(pageList); } /// /// 信息 /// /// 主键值 /// [HttpGet("Info/{id}")] public async Task GetInfo_Api(string id) { var data = await GetInfo(id); var output = data.Adapt(); return output; } #endregion #region Post /// /// 新建 /// /// 实体对象 /// [HttpPost("")] public async Task Create([FromBody] TimeTaskCrInput input) { if (await _timeTaskRepository.AnyAsync(x => x.EnCode == input.enCode && x.DeleteMark == null) || await _timeTaskRepository.AnyAsync(x => x.FullName == input.fullName && x.DeleteMark == null)) throw NCCException.Oh(ErrorCode.COM1004); var comtentModel = input.executeContent.Deserialize(); var entity = input.Adapt(); entity.ExecuteCycleJson = comtentModel.cron; var result = await Create(entity); _ = result ?? throw NCCException.Oh(ErrorCode.COM1000); // 添加到任务调度里 AddTimerJob(result); } /// /// 更新 /// /// 主键值 /// 实体对象 /// [HttpPut("{id}")] public async Task Update(string id, [FromBody] TimeTaskUpInput input) { if (await _timeTaskRepository.AnyAsync(x => x.Id != id && x.EnCode == input.enCode && x.DeleteMark == null) || await _timeTaskRepository.AnyAsync(x => x.Id != id && x.FullName == input.fullName && x.DeleteMark == null)) throw NCCException.Oh(ErrorCode.COM1004); var entityOld = await GetInfo(id); // 先从调度器里取消 SpareTime.Cancel(entityOld.Id + entityOld.EnCode); var entityNew = input.Adapt(); var isOk = await Update(entityNew); if (isOk < 1) throw NCCException.Oh(ErrorCode.COM1001); var comtentModel = entityNew.ExecuteContent.Deserialize(); // 再添加到任务调度里 if (entityOld.EnabledMark == 1) { AddTimerJob(entityNew); } } /// /// 删除 /// /// 主键值 /// [HttpDelete("{id}")] public async Task Delete(string id) { var entity = await GetInfo(id); if (entity == null) throw NCCException.Oh(ErrorCode.COM1005); var isOk = await Delete(entity); if (isOk < 1) throw NCCException.Oh(ErrorCode.COM1002); // 从调度器里取消 SpareTime.Cancel(entity.Id); } /// /// 停止 /// /// 主键值 /// [HttpPut("{id}/Actions/Stop")] public async Task Stop(string id) { var entity = await GetInfo(id); entity.EnabledMark = 0; var isOk = await Update(entity); if (isOk < 1) throw NCCException.Oh(ErrorCode.COM1003); SpareTime.Stop(entity.Id); } /// /// 启动 /// /// 主键值 /// [HttpPut("{id}/Actions/Enable")] public async Task Enable(string id) { var entity = await GetInfo(id); entity.EnabledMark = 1; var isOk = await Update(entity); if (isOk < 1) throw NCCException.Oh(ErrorCode.COM1003); if (SpareTime.AnyTask(id)) { SpareTime.Start(entity.Id); } else { AddTimerJob(entity); } } #endregion #region PublicMethod /// /// 新增定时任务 /// /// [NonAction] public void AddTimerJob(TimeTaskEntity input) { input.ExecuteCycleJson = input.ExecuteContent.Deserialize().cron; Action action = async (timer, count) => { var msg = await PerformJob(input.ExecuteType, input.ExecuteContent.Deserialize(), input.Id, null); var nextRunTime = ((DateTimeOffset)SpareTime.GetCronNextOccurrence(input.ExecuteCycleJson)).DateTime; DbScoped.SugarScope.Updateable().SetColumns(x => new TimeTaskEntity() { RunCount = x.RunCount + 1, LastRunTime = DateTime.Now, NextRunTime = nextRunTime, LastModifyUserId = "admin", LastModifyTime = DateTime.Now } ).Where(x => x.Id == input.Id).ExecuteCommand(); var status = msg.IsNullOrEmpty() ? 2 : 3; var spareTimerExecuter = new SpareTimerExecuter(timer, status, msg); await _spareTimeListener.OnListener(spareTimerExecuter); }; //创建定时任务 SpareTime.Do(input.ExecuteCycleJson, action, input.Id, input.Description, true, executeType: SpareTimeExecuteTypes.Parallel); } /// /// 启动自启动任务 /// [NonAction] public void StartTimerJob() { var list = _timeTaskRepository.Entities.Where(x => x.DeleteMark == null && x.EnabledMark.Equals(1)).ToList(); //查询数据库现有开启的定时任务列表 list.ForEach(AddTimerJob); } /// /// 详情 /// /// /// /// [NonAction] public async Task GetInfo(string id, Dictionary tenantDic = null) { return await _timeTaskRepository.FirstOrDefaultAsync(x => x.Id == id && x.DeleteMark == null); } /// /// 列表 /// /// [NonAction] public async Task> GetList() { return await _timeTaskRepository.Entities.Where(x => x.DeleteMark == null).ToListAsync(); } /// /// 新增 /// /// /// [NonAction] public async Task Create(TimeTaskEntity entity) { return await _timeTaskRepository.Context.Insertable(entity).CallEntityMethod(m => m.Creator()).ExecuteReturnEntityAsync(); } /// /// 新增日志 /// /// /// /// [NonAction] public async Task CreateTaskLog(TimeTaskLogEntity entity, Dictionary tenantDic = null) { return await _timeTaskLogRepository.InsertAsync(entity); } /// /// 删除 /// /// /// [NonAction] public async Task Delete(TimeTaskEntity entity) { return await _timeTaskRepository.Context.Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.Delete()).ExecuteCommandAsync(); } /// /// 修改 /// /// /// /// [NonAction] public async Task Update(TimeTaskEntity entity, Dictionary tenantDic = null) { return await _timeTaskRepository.Context.Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync(); } #endregion #region PrivateMethod /// /// 根据类型执行任务 /// /// /// /// /// private async Task PerformJob(string type, ContentModel model, string id, Dictionary tenantDic) { var msg = ""; if (type == "1") { msg = await Connector(model, id); } else { msg = Storage(model, id, tenantDic); } return msg; } /// /// 接口 /// /// /// private async Task Connector(ContentModel model, string id) { try { var parameters = new Dictionary(); var headersString = App.HttpContext != null && _userManager != null ? string.Format("{\"{0}\":\"{1}\"}", "Authorization", _userManager.ToKen) : null; var headers = string.IsNullOrEmpty(headersString) ? null : JSON.Deserialize>(headersString); foreach (var item in model.storedParameter) { parameters.Add(item.Key, item.Value); } switch (model.interfaceType.ToLower()) { case "get": await model.interfaceUrl.SetHeaders(headers).SetQueries(parameters).GetAsStringAsync(); break; case "post": await model.interfaceUrl.SetHeaders(headers).SetBody(parameters).PostAsStringAsync(); break; default: break; } return ""; } catch (Exception ex) { return ex.Message; } } /// /// 存储过程 /// /// /// /// public string Storage(ContentModel model, string id, Dictionary tenantDic) { try { List parameters = new List(); foreach (var item in model.storedParameter) { SugarParameter sugarParameter = new SugarParameter("@" + item.Key, item.Value); parameters.Add(sugarParameter); } if (!model.database.Equals("0")) { if (!db.IsAnyConnection(model.database)) { var link = _dblikServer.GetInfo(model.database).Result; _dataBaseService.AddConnection(link); } var otherDB = db.GetConnection(model.database); otherDB.Ado.UseStoredProcedure().GetDataTable(model.stored, parameters); } else { db.Ado.UseStoredProcedure().GetDataTable(model.stored, parameters); } return ""; } catch (Exception ex) { return ex.Message; } } #endregion } }