/// <summary> /// Позволяет инициировать немедленный запуск задачи в отдельном объекте <see cref="Task"/>. /// </summary> /// <param name="taskDescription">Запускаемая задача.</param> /// <return>Возвращает объект <see cref="Task"/>.</return> public Task <TaskExecuted> ExecuteTask(TaskDescription taskDescription) { if (!_taskList.Any(x => x.Value == taskDescription)) { throw new InvalidOperationException("Задача не зарегистрирована."); } return(Task.Factory.StartNew(() => ExecuteTaskInternal(taskDescription))); }
/// <summary> /// Позволяет изменить состояние задачи. /// </summary> /// <param name="taskDescription">Зарегистрированная задача.</param> /// <param name="isEnabled">Новое состояние задачи.</param> /// <exception cref="ArgumentNullException">Возникает, если <paramref name="taskDescription"/> равен null.</exception> /// <exception cref="InvalidOperationException">Возникает, если задача не зарегистрирована.</exception> /// <exception cref="InvalidOperationException">Возникает, если для задачи запрещено изменение состояния (см. <see cref="TaskOptions.AllowDisabling"/>).</exception> public void SetTaskEnabled(TaskDescription taskDescription, bool isEnabled) { if (taskDescription == null) { throw new ArgumentNullException(nameof(taskDescription)); } if (!_taskList.TryGetValue(taskDescription.UniqueKey, out var taskDescription2)) { throw new InvalidOperationException("Неизвестная задача."); } if (!taskDescription2.TaskOptions.HasFlag(TaskOptions.AllowDisabling)) { throw new InvalidOperationException("Для задачи запрещено изменение состояния."); } taskDescription2.IsEnabled = isEnabled; taskDescription.IsEnabled = isEnabled; }
private TaskExecuted ExecuteTaskInternal(TaskDescription taskDescription) { if (!_executeFlags.TryLock(taskDescription.UniqueKey) && taskDescription.TaskOptions.HasFlag(TaskOptions.PreventParallelExecution)) { return(TaskExecuted.ParallelPrevented); } try { var idItemType = Core.Items.ItemTypeFactory.GetItemType <Db.Task>().IdItemType; var itemKey = new Core.Items.ItemKey(idItemType, taskDescription.Id); if (!(taskDescription.JournalOptions != null && taskDescription.JournalOptions.LimitByLastNDays.HasValue && taskDescription.JournalOptions.LimitByLastNDays <= 0)) { this.RegisterEventForItem(itemKey, Journaling.EventType.Info, "Запуск", $"Запуск задачи '{taskDescription.Name}' (№{taskDescription.Id} / '{taskDescription.UniqueKey}')."); } var timeStart = DateTime.Now; taskDescription.ExecutionLambda.Compile().Invoke(); if (!(taskDescription.JournalOptions != null && taskDescription.JournalOptions.LimitByLastNDays.HasValue && taskDescription.JournalOptions.LimitByLastNDays <= 0)) { this.RegisterEventForItem(itemKey, Journaling.EventType.Info, "Завершение", $"Задача '{taskDescription.Name}' (№{taskDescription.Id} / '{taskDescription.UniqueKey}') выполнена за {Math.Round((DateTime.Now - timeStart).TotalSeconds, 3)} сек."); } return(TaskExecuted.Executed); } catch (Exception ex) { if (!(taskDescription.JournalOptions != null && taskDescription.JournalOptions.LimitByLastNDays.HasValue && taskDescription.JournalOptions.LimitByLastNDays <= 0)) { this.RegisterEvent(Journaling.EventType.Info, "Ошибка выполнения", $"Неожиданная ошибка выполнения задачи '{taskDescription.Name}' (№{taskDescription.Id} / '{taskDescription.UniqueKey}').", ex); } return(TaskExecuted.Faulted); } finally { _executeFlags.ReleaseLock(taskDescription.UniqueKey); } }
private void PrepareTaskSchedules(TaskDescription taskDescription) { foreach (var schedule in taskDescription.ManualSchedules) { var scheduleUniqueKey = schedule.GetUniqueKey(); var uniqueKey = $"task_{taskDescription.UniqueKey}_sc_{scheduleUniqueKey}"; if (!schedule.IsEnabled) { lock (_jobsSyncRoot) { _jobsList.RemoveAll(x => x.JobName == uniqueKey); } continue; } if (schedule is TaskCronSchedule taskCronSchedule) { SetTask(uniqueKey, taskCronSchedule.CronExpression, () => ExecuteTaskStatic(taskDescription.UniqueKey, scheduleUniqueKey)); } else if (schedule is TaskFixedTimeSchedule taskFixedTimeSchedule) { SetTask(uniqueKey, taskFixedTimeSchedule.DateTime, () => ExecuteTaskStatic(taskDescription.UniqueKey, scheduleUniqueKey)); } } foreach (var schedule in taskDescription.Schedules) { var scheduleUniqueKey = schedule.GetUniqueKey(); var uniqueKey = $"task_{taskDescription.UniqueKey}_sc_{scheduleUniqueKey}"; if (schedule is TaskCronSchedule taskCronSchedule) { SetTask(uniqueKey, taskCronSchedule.CronExpression, () => ExecuteTaskStatic(taskDescription.UniqueKey, scheduleUniqueKey)); } else if (schedule is TaskFixedTimeSchedule taskFixedTimeSchedule) { SetTask(uniqueKey, taskFixedTimeSchedule.DateTime, () => ExecuteTaskStatic(taskDescription.UniqueKey, scheduleUniqueKey)); } } }
private TaskDescription UpdateTask(TaskDescription taskDescription, TaskRequest taskRequest) { using (var db = new Db.DataContext()) { var taskDb = db.Task.Where(x => x.UniqueKey == taskRequest.UniqueKey).Include(x => x.TaskSchedules).FirstOrDefault(); if (taskDb == null) { taskDb = new Db.Task() { Name = taskRequest.Name, Description = taskRequest.Description, IsEnabled = null, TaskSchedules = new List <Db.TaskSchedule>(), UniqueKey = taskRequest.UniqueKey }; db.Task.Add(taskDb); db.SaveChanges(); } taskDb.Name = taskRequest.Name; taskDb.Description = taskRequest.Description; if (!taskRequest.TaskOptions.HasFlag(TaskOptions.AllowDisabling)) { taskDb.IsEnabled = null; } if (!taskRequest.TaskOptions.HasFlag(TaskOptions.AllowManualSchedule) && taskDb.TaskSchedules.Count > 0) { db.TaskSchedule.RemoveRange(taskDb.TaskSchedules); taskDb.TaskSchedules.Clear(); } db.SaveChanges(); var schedules = new List <TaskSchedule>(); foreach (var scheduleDb in taskDb.TaskSchedules) { TaskSchedule taskSchedule = null; if (scheduleDb.DateTimeFixed.HasValue) { taskSchedule = new TaskFixedTimeSchedule(new DateTimeOffset(scheduleDb.DateTimeFixed.Value.Ticks, TimeSpan.Zero)); } else if (!string.IsNullOrEmpty(scheduleDb.Cron)) { taskSchedule = new TaskCronSchedule(scheduleDb.Cron); } if (taskSchedule == null) { continue; } taskSchedule.IsEnabled = scheduleDb.IsEnabled; schedules.Add(taskSchedule); } taskDescription.Id = taskDb.Id; taskDescription.Name = taskRequest.Name; taskDescription.Description = taskRequest.Description; taskDescription.ExecutionLambda = taskRequest.ExecutionLambda; taskDescription.IsConfirmed = true; taskDescription.UniqueKey = taskRequest.UniqueKey; taskDescription.IsEnabled = taskDb.IsEnabled ?? taskRequest.IsEnabled; taskDescription.TaskOptions = taskRequest.TaskOptions; taskDescription.Schedules = new ReadOnlyCollection <TaskSchedule>(taskRequest.Schedules ?? new List <TaskSchedule>()); taskDescription.ManualSchedules = new ReadOnlyCollection <TaskSchedule>(schedules.GroupBy(x => x.GetUniqueKey()).Select(x => x.First()).ToList()); taskDescription.JournalOptions = taskRequest.JournalOptions; } return(taskDescription); }
/// <summary> /// Позволяет изменить список дополнительных правил задачи. /// </summary> /// <param name="taskDescription">Зарегистрированная задача.</param> /// <param name="scheduleList">Список правил задачи.</param> /// <exception cref="ArgumentNullException">Возникает, если <paramref name="taskDescription"/> равен null.</exception> /// <exception cref="InvalidOperationException">Возникает, если задача не зарегистрирована.</exception> /// <exception cref="InvalidOperationException">Возникает, если для задачи запрещено изменение списка правил (см. <see cref="TaskOptions.AllowManualSchedule"/>).</exception> public void SetTaskManualScheduleList(TaskDescription taskDescription, List <TaskSchedule> scheduleList) { if (taskDescription == null) { throw new ArgumentNullException(nameof(taskDescription)); } if (!_taskList.TryGetValue(taskDescription.UniqueKey, out var taskDescription2)) { throw new InvalidOperationException("Неизвестная задача."); } if (!taskDescription2.TaskOptions.HasFlag(TaskOptions.AllowManualSchedule)) { throw new InvalidOperationException("Для задачи запрещено изменение списка правил."); } if (scheduleList?.GroupBy(x => x.GetUniqueKey()).Any(x => x.Count() > 1) ?? false) { throw new ArgumentException("В списке есть повторяющиеся правила запуска.", nameof(scheduleList)); } try { var schedules = scheduleList?.ToDictionary(x => x.GetUniqueKey(), x => x); var collection = new ReadOnlyCollection <TaskSchedule>(scheduleList ?? new List <TaskSchedule>()); using (var db = new Db.DataContext()) { var list = db.TaskSchedule.Where(x => x.IdTask == taskDescription2.Id).ToList(); var listToRemove = list.Where(x => !schedules.ContainsKey(x.GetUniqueKey())).ToList(); db.TaskSchedule.RemoveRange(listToRemove); var isChanged = listToRemove.Count > 0; list.Where(x => schedules.ContainsKey(x.GetUniqueKey())).ForEach(x => { isChanged = isChanged || x.IsEnabled != schedules[x.GetUniqueKey()].IsEnabled; x.IsEnabled = schedules[x.GetUniqueKey()].IsEnabled; }); schedules.ForEach(pair => { if (!list.Any(x => x.GetUniqueKey() == pair.Key)) { if (pair.Value is TaskCronSchedule taskCronSchedule) { isChanged = true; db.TaskSchedule.Add(new Db.TaskSchedule() { IdTask = taskDescription2.Id, IsEnabled = pair.Value.IsEnabled, Cron = taskCronSchedule.CronExpression }); } else if (pair.Value is TaskFixedTimeSchedule taskFixedTimeSchedule) { isChanged = true; db.TaskSchedule.Add(new Db.TaskSchedule() { IdTask = taskDescription2.Id, IsEnabled = pair.Value.IsEnabled, DateTimeFixed = taskFixedTimeSchedule.DateTime.UtcDateTime }); } } }); if (isChanged) { db.SaveChanges(); } taskDescription2.ManualSchedules = collection; taskDescription.ManualSchedules = collection; PrepareTaskSchedules(taskDescription2); } } catch (Exception ex) { this.RegisterEvent(Journaling.EventType.CriticalError, "Ошибка во время сохранения списка правил", null, ex); throw new Exception("Неожиданная ошибка во время сохранения списка правил."); } }
/// <summary> /// Возвращает список задач. /// </summary> /// <param name="onlyConfirmed">Если равно true, то возвращает только подтвержденные задачи (см. <see cref="TaskDescription.IsConfirmed"/>.</param> public List <TaskDescription> GetTaskList(bool onlyConfirmed) { try { var list = _taskList.Values.ToDictionary(x => x.Id, x => x); if (!onlyConfirmed) { using (var db = new Db.DataContext()) { var query = db.Task.Include(x => x.TaskSchedules); var taskList = query.ToList(); foreach (var taskDb in taskList) { if (list.ContainsKey(taskDb.Id)) { continue; } var schedules = new List <TaskSchedule>(); foreach (var scheduleDb in taskDb.TaskSchedules) { TaskSchedule taskSchedule = null; if (scheduleDb.DateTimeFixed.HasValue) { taskSchedule = new TaskFixedTimeSchedule(new DateTimeOffset(scheduleDb.DateTimeFixed.Value.Ticks, TimeSpan.Zero)); } else if (!string.IsNullOrEmpty(scheduleDb.Cron)) { taskSchedule = new TaskCronSchedule(scheduleDb.Cron); } if (taskSchedule == null) { continue; } taskSchedule.IsEnabled = scheduleDb.IsEnabled; schedules.Add(taskSchedule); } var taskDescription = new TaskDescription { Id = taskDb.Id, Name = taskDb.Name, Description = taskDb.Description, ExecutionLambda = null, IsConfirmed = false, UniqueKey = taskDb.UniqueKey, IsEnabled = taskDb.IsEnabled ?? false, TaskOptions = TaskOptions.None, Schedules = new ReadOnlyCollection <TaskSchedule>(new List <TaskSchedule>()), ManualSchedules = new ReadOnlyCollection <TaskSchedule>(schedules) }; list[taskDb.Id] = taskDescription; } } } return(list.Values.ToList()); } catch (Exception ex) { this.RegisterEvent(Journaling.EventType.CriticalError, "Ошибка во время получения списка задач", null, ex); throw new Exception("Неожиданная ошибка во время получения списка задач."); } }