Creating custom scheduler

This article illustrates creating a system scheduler that checks every day, which projects are due on the next day. After the scheduler task has been completed, project managers will receive system notifications about project end date.

Example of data display 

Fig. 1. “Project end date” scheduler

Fig. 1. “Project end date” scheduler

Fig. 2. System notification

Fig. 2. System notification

Methods of the ISchedulerJobRepository extension (interface)

The ISchedulerJobRepository extension point (interface) has the following methods:

/// <summary>
/// Get the list of scheduled tasks
/// </summary>
/// <returns></returns>
ICollection<ISchedulerJob> GetSchedulerJobs();

To implement the scheduler extension point, you have to implement the interface of the scheduler job

Methods of the ISchedulerJob extension (interface)

/// <summary>
/// Owner UID
/// If you need the scheduler to be in a separate unit,you have to implement <seealso cref="ISchedulerTaskOwner"/> and specify its Uid
/// </summary>
Guid? OwnerUid { get; }
 
/// <summary>
/// Trigger
/// </summary>
[NotNull]
ITrigger Trigger { get; }
 
/// <summary>
/// List of executed jobs
/// </summary>
[NotNull]
ICollection<IJob> Jobs  { get; }

The ISchedulerJob interface has the following methods:

Methods of the ISchedulerTaskOwner extension (interface)

The ISchedulerTaskOwner extension point (interface) has the following methods:

/// <summary>
/// Owner UID
/// </summary>
Guid Uid { get; }
 
/// <summary>
/// Owner name
/// </summary>
string Name { get; }

Example of a class of the ISchedulerTaskOwner, ISchedulerJobRepository and ISchedulerJob extension points

[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 "Scheduler for checking project end date"; }
 }
}
 
[Component]
public class Scheduler : ISchedulerJobRepository
{
 /// <summary>
 /// Trigger UID
 /// </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,//Scheduler type (daily, monthly, weekly, one-time)
     DailySettings = new DailySettings { EveryDay = 1, OnlyWorkDays = false },//Depending on the type, configure scheduler settings:EveryDay – each Nth day, OnlyWorkDays – only on business days
     StartDate = DateTime.Today.AddMinutes(30),//Start date (when the scheduler will be started, in this case 00:30)
     OvertimeToRun = TimeSpan.FromDays(1)//Time, after which the task can still be executed,if for some reason it didn’t happen in time(e.g. the server was down)
     //You can add RepeatSettings, for example, to run the scheduler automatically every minute 
     //Example: RepeatSettings = new RepeatSettings {Enabled = true, RepeatEvery = TimeSpan.FromMinutes(1), RepeatTo = TimeSpan.FromHours(24)},
    },
    Locator.GetService<IProductionCalendarService>())
   {
    Name = SR.T("Trigger for checking project end date"),//Name of the unit with reminders
    Id = TriggerGuid //Scheduler ID
   };
   _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; }//Return null, if you need the scheduler in the "System" unit
  }
 
  private class MessageScheduler : IJob
  {
   public Guid Id
   {
    get { return new Guid("94A8F714-01D8-4472-85F2-417167075CAE"); }
   }
 
   public string Name
   {
    get { return SR.T("Check project end date"); }
   }
 
   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("A project end date is tomorrow:{0}", project.FinishDate);
       message.FullMessage = string.Format("Project: {0}", project.Name);
       message.Recipients.Add(project.Manager);
       message.Save();
      }
     }
    });
 
    return new JobResult
    {
     Status = JobStatus.Success,
     Information = SR.T("Check project end date")
    };
   }
  }
 }
}

As you can see, the scheduler job in the public JobResult Do(DateTime dateToRun) method is executed on behalf of the system (by default, when executing scheduler job, the current user is not defined). Then the list of active projects is filtered by end date and those project, whose end date is on the next day are selected. After that, each project manager receives a system notification.

Links to API elements

ISchedulerJobRepository
ISchedulerJob
ISchedulerTaskOwner

 

Attachments