[ELMA3] Создание собственного планировщика
В статье приведен пример создания системного ежедневного планировщика, который каждый день в 0:30 проверяет, у каких проектов срок сдачи будет на следующий день. После выполнения задачи планировщика менеджерам проектов будут отправлены сообщения от имени системы о том, что завтра срок проекта заканчивается.
Пример отображения данных
Рис. 1. Планировщик «Проверка завершения проекта»
Рис. 2. Сообщение в ленте сообщений у менеджера проекта, по которому завершается срок сдачи
Методы расширения (интерфейса) ISchedulerJobRepository
Точка расширения (интерфейс) ISchedulerJobRepository имеет следующие методы:
/// <summary> /// Получить список запланированных задач /// </summary> /// <returns></returns> ICollection<ISchedulerJob> GetSchedulerJobs();
Для реализации точки расширения планировщика, необходимо реализовать интерфейс запланированной работы планировщика
Методы расширения (интерфейса) ISchedulerJob
Интерфейс ISchedulerJob имеет следующие методы:
/// <summary> /// Уникальный идентификатор владельца /// Если нужно, чтобы планировщик не был в блоке "Системные" необходимо реализовать <seealso cref="ISchedulerTaskOwner"/> и указать его Uid /// </summary> Guid? OwnerUid { get; } /// <summary> /// Триггер /// </summary> [NotNull] ITrigger Trigger { get; } /// <summary> /// Список выполняемых работ /// </summary> [NotNull] ICollection<IJob> Jobs { get; }
Методы расширения (интерфейса) ISchedulerTaskOwner
Точка расширения (интерфейс) ISchedulerTaskOwner имеет следующие методы:
/// <summary> /// Уникальный идентификатор владельца /// </summary> Guid Uid { get; } /// <summary> /// Имя владельца /// </summary> string Name { get; }
Пример класса точки расширения ISchedulerTaskOwner, ISchedulerJobRepository и ISchedulerJob
[Component] public class Owner : ISchedulerTaskOwner { public static readonly Guid Trigguid = new Guid("E2460CB3-5571-4130-A1E2-883882B1D164"); public Guid Uid { get { return Trigguid; } } public string Name { get { return "Планировщик по проверке завершения проекта"; } } } [Component] public class Scheduler : ISchedulerJobRepository { /// <summary> /// Уникальный идентификатор триггера /// </summary> public static readonly Guid TriggerGuid = new Guid("5D9991B5-47E0-4f54-8B4E-0CA72A232A12"); public ICollection<ISchedulerJob> GetSchedulerJobs() { return new ISchedulerJob[] { new MessageSchedulerJob() }; } private class MessageSchedulerJob : ISchedulerJob { private readonly ITrigger _trigger; private readonly ICollection<IJob> _jobs; public MessageSchedulerJob() { _trigger = new NthIncludedDayTrigger( new NthIncludedDaySettings { ScheduleType = ScheduleType.Daily, //Тип планировщика (Ежедневный, ежемесячный, еженедельный, одиночный) DailySettings = new DailySettings { EveryDay = 1, OnlyWorkDays = false }, //В зависимости от типа задаются настройки планировщика: EveryDay - каждый N-ый день, OnlyWorkDays - только по рабочим дням StartDate = DateTime.Today.AddMinutes(30), //Дата начала (во сколько планировщик будет запущен, в данном случае в 00:30) OvertimeToRun = TimeSpan.FromDays(1) //Время, через которое еще можно выполнить задачу, если в нужное время выполнить не получилось по какой-то причине (например не был запущен сервер) //Можно добавить RepeatSettings - настройки повтора планировщика, чтобы, например, автоматически выполнялся каждую минуту //Пример: RepeatSettings = new RepeatSettings {Enabled = true, RepeatEvery = TimeSpan.FromMinutes(1), RepeatTo = TimeSpan.FromHours(24)}, }, Locator.GetService<IProductionCalendarService>()) { Name = SR.T("Триггер проверки завершения проекта"), //Название блока с вашими напоминаниями Id = TriggerGuid //Идентификатор планировщика }; _jobs = new List<IJob> { new MessageScheduler() }; } public ITrigger Trigger { get { return _trigger; } } public ICollection<IJob> Jobs { get { return _jobs; } } public virtual Guid? OwnerUid { get { return Owner.Trigguid; } //Вернуть null, если нужно, чтобы планировщик был в блоке "Системные" } private class MessageScheduler : IJob { public Guid Id { get { return new Guid("94A8F714-01D8-4472-85F2-417167075CAE"); } } public string Name { get { return SR.T("Проверка завершения проекта"); } } public Image Icon { get { return null; } } public JobResult Do(DateTime dateToRun) { var user = UserManager.Instance.LoadOrNull(SecurityConstants.SystemUserUid); Locator.GetServiceNotNull<ISecurityService>().RunByUser(user, () => { var filter = InterfaceActivator.Create<IProjectFilter>(); filter.FinishDate = new RelativeDateTime(DateTime.Today.AddDays(1), DateTime.Today.AddDays(1)); filter.Status = ProjectStatus.Active; filter.DisableSecurity = true; var projectsendtoday = ProjectManager.Instance.Find(filter, null); if (projectsendtoday.Count != 0) { foreach (var project in projectsendtoday) { var message = ChannelMessageManager.Instance.Create(); message.CreationDate = dateToRun; message.CreationAuthor = user; message.Subject = string.Format("У следующего проекта заканчивается срок сдачи: {0}", project.FinishDate); message.FullMessage = string.Format("Наименование проекта: {0}", project.Name); message.Recipients.Add(project.Manager); message.Save(); } } }); return new JobResult { Status = JobStatus.Success, Information = SR.T("Проверка завершения проекта") }; } } } }
Как можно заметить, в методе public JobResult Do(DateTime dateToRun) работа планировщика выполняется от имени системы (по умолчанию при выполнении работы планировщика текущий пользователь не задан), затем фильтруется список активных проектов по дате завершения и отбираются только те, чья дата завершения будет завтра, затем создается сообщение в ленту сообщений для каждого менеджера по каждому проекту, автором сообщения является система.