Add Native Support for RRULE (iCalendar Recurrence) in Hangfire

I’m proposing the addition of RRULE support in Hangfire, similar to the recurrence rules used in Google Calendar’s ICS files. Currently, Hangfire relies on Cron expressions for scheduling, but they fall short in scenarios where precise recurrence is needed, as defined by RRULE.

Problem:
Consider the following examples:

FREQ=MINUTELY;INTERVAL=7 => Cron: */7 * * * *
FREQ=HOURLY;INTERVAL=7 => Cron: 5 */7 * * *
FREQ=DAILY;INTERVAL=7 => Cron: 5 3 */7 * *
FREQ=WEEKLY;INTERVAL=2;BYDAY=TH,SA;UNTIL=20240831T175959Z
FREQ=MONTHLY;INTERVAL=2;BYMONTHDAY=19;COUNT=3
FREQ=YEARLY;INTERVAL=2;BYYEARDAY=228

For example, the Cron expression for FREQ=MINUTELY;INTERVAL=7 is */7 * * * *, which triggers at the 0th, 7th, 14th, 21st, etc., minute within each hour. However, this does not align with the intended behavior of running a job every 7 minutes from a specific start time.

Let’s say the first job runs at 00:07 (7th minute). The next expected run time should be 00:14, followed by 00:21, and so on. The issue arises at the 56th minute. After 00:56, the Cron expression */7 * * * * schedules the next run at 01:00, which is incorrect according to the RRULE. The correct next run time should be 01:03 (7 minutes after 00:56), as the job should run every 7 minutes continuously, not reset at the start of the hour.

This problem exists across all types of frequencies where Cron expressions are used, leading to misaligned scheduling when intervals span across hours, days, or other time units.

Proposed Solutions:

Sol 1 - Recurring Job with Frequent (Every minute, hour, daily, monthly based on the FREQ) Trigger:

Set up a recurring job to trigger every minute (* * * * *) or hour ( 5 * * * *), depending on the frequency.
Use a library like ICal.NET to check whether the current time matches the next occurrence based on the RRULE.

Problem: This solution can lead to a significant increase in server load, as the job triggers frequently and performs additional checks, which is inefficient.

Sol 2 - Dynamically Register Next Job:

Calculate the first occurrence of the job based on the RRULE and register a scheduled job.
When the job executes, calculate the next occurrence and register a new scheduled job accordingly.

Problem: While this reduces server load by only triggering jobs when needed, it introduces complexity. If the server fails to register the next job due to downtime or other issues, the recurrence chain could break. Although Hangfire preserves jobs if the server is temporarily down, there are still edge cases where failures could disrupt the job schedule.

Example Code:
Here’s a basic example using ICal.NET to get the next occurrence:

string rrule = "FREQ=HOURLY;INTERVAL=7";
var pattern = new RecurrencePattern(rrule);
string start = "2024-08-23T06:00:00.000Z";
var startDate = DateTime.Parse(start, null, System.Globalization.DateTimeStyles.RoundtripKind);
var calendarEvent = new CalendarEvent
{
    Start = new CalDateTime(startDate),
    RecurrenceRules = new List<RecurrencePattern> { pattern },
};
var occurrences = calendarEvent.GetOccurrences(DateTime.UtcNow, DateTime.UtcNow.AddYears(1))
    .Select(x => x.Period.StartTime.AsUtc).ToList();

Expectation:
It would be highly beneficial for Hangfire to support RRULEs natively, as this is a common requirement for scheduling tasks, especially in applications that handle calendar-like events. Moreover, RRULEs can also include complex exception rules, which are difficult to manage with Cron alone.

Is anyone else encountering similar challenges? How have you addressed them? I’d love to hear your solutions or thoughts on this feature request.

Github Issue: Add Support for RRULE (iCalendar Recurrence) in Hangfire · Issue #2435 · HangfireIO/Hangfire · GitHub

1 Like

I have implement some solutions here

If you face same problem see this. Any kind of feedback will be appreciated