Search code examples
azurecronazure-webjobs

Setting Cron expressions on different day and different time


I have a Azure webjob which runs once a week at 1.30pm. Now I need to change the schedule and here is the schedule for the week.

Monday at 3pm
Tuesday at 7pm
Friday at 12pm

This following expression runs for every Monday (* 01 30 * * 1). I can change that to run on different days at the same time at 1.30pm (* 01 30 * * 1,2,5), but not sure how to make different timings for different days.

* 01 30 * * 1 
* 01 30 * * 1,2,5

Solution

  • There are three ways I know to implement it.

    1. The simplest way, create multiple static webjob method in Function.cs like this.

      // Function triggered by a timespan schedule every 15 sec.
      public static void TimerJob([TimerTrigger("00:00:15")] TimerInfo timerInfo, 
                                  TextWriter log)
      {
          log.WriteLine("1st scheduled job fired!");
      }
      
      // Function triggered by a timespan schedule every 5 minute.
      public static void TimerJob([TimerTrigger("0 */5 * * * *")] TimerInfo timerInfo, 
                                  TextWriter log)
      {
          log.WriteLine("2nd scheduled job fired!");
      }
      
    2. Use a CustomSchedule class to define the schedule. This is the webjob sample in the github, and is with weekly or monthly, you will need define the timespan in app.config like this.

      <appSettings> <add key="Mon" value="08:11:20|09:24:20|09:28:20"/> <add key="Tue" value="09:19:40"/> <add key="Wed" value="09:15:40"/> <add key="Thu" value="09:15:40"/> <add key="Fri" value="09:15:40"/> <add key="Sat" value="09:15:40"/> <add key="Sun" value="09:15:40"/> </appSettings>

    3. This way is similar to the second way, use [TimerSchedule] abstract class to build custom scheduler that supports multiple cron expressions. Further more information you could refer to this blog:Combining cron expressions in Azure WebJobs TimerTriggers.

      public class CombinedCronSchedule : TimerSchedule
      {
      private readonly Func<IEnumerable<DateTime>, DateTime> _nextOccurenceSelector;
      private readonly IReadOnlyCollection<CronSchedule> _schedules;
      
      public CombinedCronSchedule(params string[] expressions) : this(dates => dates.Min(), expressions)
      {
      }
      
      public CombinedCronSchedule(Func<IEnumerable<DateTime>, DateTime> nextOccurenceSelector, params string[] expressions)
      {
          _nextOccurenceSelector = nextOccurenceSelector;
          _schedules = expressions.Select(s => new CronSchedule(s)).ToList();
      }
      
      public override DateTime GetNextOccurrence(DateTime now)
      {
          return _nextOccurenceSelector(_schedules.Select(s => s.GetNextOccurrence(now)));
      }
      
      public override string ToString()
      {
          var schedules = string.Join(", ", _schedules.Select(s => s.ToString()));
          return $"Schedules: {schedules}";
      }
      }
      

      Create a class that represents our new schedule:

      public class PeakNonPeakSchedule : CombinedCronSchedule
      {
          // Every 15 minutes, between 06:00 AM and 08:59 PM
          private const string PeakHours = "0 */15 6-20 * * *";
      
          // Every hour from 12:00 AM to 06:00 AM and 09:00 PM to 12:00 AM
          private const string NonPeakHours = "0 0 0-5,21-23 * * *";
      
          public PeakNonPeakSchedule() : base(PeakHours, NonPeak)
          {
          }
      }
      

      Create your job.

      public static void Cleanup([TimerTrigger(typeof(PeakNonPeakSchedule))] TimerInfo timer)
      {
          DoCleanup();
      }
      
      // No second job needed!
      

    Hope this could help you.