using Microsoft.Extensions.Logging; using Repository.BackendRepository.Implement; using Repository.BackendRepository.Interface; using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; using System.Threading.Tasks; using NCrontab; using static NCrontab.CrontabSchedule; using Org.BouncyCastle.Utilities; namespace BackendWorkerService.Quartz { /// /// Job調度中間對象 /// public class JobSchedule { public JobSchedule(Type jobType, string cronExpression) { this.JobType = jobType ?? throw new ArgumentNullException(nameof(jobType)); CronExpression = cronExpression ?? throw new ArgumentNullException(nameof(cronExpression)); } /// /// Job類型 /// public Type JobType { get; private set; } /// /// Cron表達式 /// public string CronExpression { get; private set; } /// /// Job狀態 /// public JobStatus JobStatu { get; set; } = JobStatus.Init; } /// /// Job運行狀態 /// public enum JobStatus : byte { [Description("初始化")] Init = 0, [Description("運行中")] Running = 1, [Description("調度中")] Scheduling = 2, [Description("已停止")] Stopped = 3, } public class Task_Detail { private readonly IBackendRepository backendRepository; private readonly ILogger logger; public Task_Detail(ILogger logger, IBackendRepository backendRepository) { this.logger = logger; this.backendRepository = backendRepository; } /// /// 取得時間規則 /// /// /// /// private async Task GetWorkRule(string task,string task_item) { string Times = null; try { var sql = $@" select b.system_value from task_detail a join variable b on a.variable_id = b.id where a.task = '{task}' and a.task_item = '{task_item}'"; Times = await backendRepository.GetOneAsync(sql); #region when dont have data if (string.IsNullOrWhiteSpace(Times)) { Times = task_item.ToLower() == "hour" ? "0 0 0/1 * * *" : task_item.ToLower() == "day" ? "0 0 0 1/1 * *" : task_item.ToLower() == "month" ? "0 0 0 1 1/1 *" : task_item.ToLower() == "year" ? "0 0 0 1 1 1/1" : task.ToLower() == "weatherapi" ? "0 0/10 * * * *" : "* * * * * *"; sql = @$"insert into variable (deleted, system_type, system_key, system_value, system_remark, system_priority, system_parent_id) values (0, 'taskTime', '{task}_{task_item}', '{Times}', '歸檔', 0, 0);"; await backendRepository.ExecuteSql(sql); sql = $@"select id from variable where system_type = 'taskTime' and system_key = '{task}_{task_item}'"; var id = await backendRepository.GetOneAsync(sql); sql = $"update task_detail set variable_id = {id} where task = '{task}' and task_item = '{task_item}'"; await backendRepository.ExecuteSql(sql); } #endregion } catch (Exception exception) { logger.LogError("【Task_Detail】【任務時間獲取失敗】"); logger.LogError("【Task_Detail】【任務時間獲取失敗】[Exception]:{0},Task:{1},task_item:{2}", exception.ToString(),task,task_item); } return Times; } /// /// 是否執行任務 /// /// /// /// public async Task GetNeedWorkTask(string task, string task_item) { try { var sql = $@"select a.lastwork_time from task_detail a where a.task = '{task}' and a.task_item = '{task_item}'"; var lastworkTime = await backendRepository.GetOneAsync(sql); if (task_item == "Compensate") { string ss = ""; } if (lastworkTime == null) { sql = $"insert into task_detail (task, task_item, lastwork_time, created_at) values ('{task}', '{task_item}', now(), now());"; await backendRepository.ExecuteSql(sql, null); } DateTime dateTime = lastworkTime != null ? Convert.ToDateTime(lastworkTime) : Convert.ToDateTime("1970-01-01 00:00:01"); //取得 variable 中的 crob 時間設定 ex: 0 0/1 * * * * var crobTime = await GetWorkRule(task, task_item); var nextTime = CrontabSchedule.Parse(crobTime, new ParseOptions { IncludingSeconds = true } ).GetNextOccurrence(dateTime); if (DateTime.Now >= nextTime) { return true; } } catch(Exception exception) { logger.LogError("【Task_Detail】【時間解析失敗】[Exception]:{0},Task:{1},task_item:{2}", exception.ToString(), task, task_item); } return false; } /// /// 紀錄任務開始執行時間 /// /// /// /// public async Task InsertWorkTime(string task, string task_item ,string LoggerWord = null) { try { Dictionary worktime = new Dictionary() { { "@lastwork_time", DateTime.Now.ToUniversalTime()}, { "@success", 2}, { "@updated_at", DateTime.Now.ToUniversalTime()}, }; await backendRepository.UpdateOneByCustomTable(worktime, "task_detail", $" task = '{task}' and task_item = '{task_item}'"); if(LoggerWord == null) { logger.LogInformation($"【Task_Detail】【開始{task},{task_item}任務】"); } logger.LogInformation($"【Task_Detail】【{LoggerWord}】"); } catch (Exception exception) { logger.LogError("【Task_Detail】【任務輸入開始時間】[Exception]:{0},Task:{1},task_item:{2}", exception.ToString(), task, task_item); } } /// /// 紀錄任務結束時間 /// /// /// /// public async Task InsertWorkTime_End(string task, string task_item,string LoggerWord = null) { try { Dictionary worktime = new Dictionary() { { "@success", 0}, { "@lastwork_end_time", DateTime.Now.ToUniversalTime()}, { "@updated_at", DateTime.Now.ToUniversalTime()}, }; await backendRepository.UpdateOneByCustomTable(worktime, "task_detail", $" task = '{task}' and task_item = '{task_item}'"); if (LoggerWord == null) { logger.LogInformation($"【Task_Detail】【結束{task},{task_item}任務】"); } logger.LogInformation($"【Task_Detail】【{LoggerWord}】"); } catch (Exception exception) { logger.LogError("【Task_Detail】【任務輸入結束時間】[Exception]:{0},Task:{1},task_item:{2}", exception.ToString(), task, task_item); } } /// /// 執行失敗紀錄 /// /// /// /// public async Task WorkFail(string task, string task_item,string reason = "") { try { Dictionary worktime = new Dictionary() { { "@success", 1}, { "@updated_at", DateTime.Now.ToUniversalTime()}, }; await backendRepository.UpdateOneByCustomTable(worktime, "task_detail", $" task = '{task}' and task_item = '{task_item}'"); logger.LogError("【Task_Detail】【任務執行失敗】[Exception]:{0},Task:{1},task_item:{2}", reason, task, task_item); } catch (Exception exception) { logger.LogError("【Task_Detail】【任務執行失敗】[Exception]:{0},Task:{1},task_item:{2}", exception.ToString(), task, task_item); } } } }