1

I have been asked to add a feature to some software I have written which needs to send reminder emails.

The reminders can have a recurrence; for example, it might recur every 3 days or every 2 weeks. The reminders also have a start and end date. I have created an SQL table with these fields:

event_id
event_name
event_Description
event_startDate
event_endDate
RecurrenceType (e.g. Daily, Weekly, Monthly,Yearly)
Intarval 
event_ActiveFlag

I now need to write a stored procedure that will run every time and send the reminders. I have no problem with sending via a C# console application; the trouble I am having is that I cannot figure out how to get the recurrences for the current day.

Esoteric Screen Name
  • 6,082
  • 4
  • 29
  • 38
  • For this one thing I could suggest is to write windows service which will either poll database for sending message or trigger on specific time. To find recurrence , you need to have structure in DB for the same which will store number of recurrences , how many executed, how many pending and type of recurrence i.e. daily, weekly,monthly. Calculate execution date and store in DB. Afer execution calculate next execution date and update. – Amit Jan 27 '15 at 07:11
  • possible duplicate of [Calculating recurrence of events using DateTime in C#](http://stackoverflow.com/questions/9821511/calculating-recurrence-of-events-using-datetime-in-c-sharp) – Esoteric Screen Name Jan 27 '15 at 07:57

1 Answers1

2

No matter what, you cannot get around needing to perform a computation to determine the list of recurrence dates for a given event. By "computation" I mean something like the following pseudocode:

foreach(event in activeEvents)
{
    while(recurrenceDate <= currentDate && recurrenceDate <= event.EndDate)
    {
      event.RecurrenceDates.Add(recurrenceDate);
      recurrenceDate.AddDays(event.IntervalLengthInDays);
    }
}

I highly recommend using Douglas Day's excellent .NET iCal library (be sure to read the license terms to ensure you are permitted to use this in your app, though they are quite permissive) to calculate recurrence dates for you, because despite appearing straightforward, it's actually very difficult to correctly handle all the corner cases.

This will give you a list of dates that the event occurs on, up to the current date. There are two questions: when and where should you perform this calculation?

As for where, I recommend in the C# app, since you've already stated you have such a component involved. It is absolutely possible to do this in a performant, set-based way in your SQL database; however, the obvious, intuitive way to code this is using loops. C# is great at loops; SQL is not. And doing it the obvious way will make it much easier to debug and maintain when you (or someone else) looks at it six months down the line.

Regarding when, there are two possibilities:

Option 1: On demand: do it as part of the job that sends your daily reminder blast.

  • Fetch the data for all active events
  • Compute recurrence lists for them
  • Examine the last recurrent event (this will be the one closest to the current date) to determine if that event should be sent out as a reminder
  • Send eligible reminders

Option 2: Once: do it when the event is created and entered in the system.

  • When an event is created, calculate all recurrence dates through its end date
  • Store these dates in a table in the DB (event_id FK, event_date)
  • Your reminder job fetches a list of eligible events (both active and has the appropriate date) from the precomputed table
  • Send eligible reminders

Which option is better? My money is on #1. Why?

  • With option 1, if I realize I accidentally entered "daily" instead of "weekly" for my recurrence period, changing the event is much easier, because I don't have recompute and re-store all the recurrence data. This is the reason to calculate recurrence on demand, and should trump all but the most dire of performance related concerns (most of which could likely be fixed by throwing more hardware at the problem, or by better load balancing).
  • Option 2 is degenerate in the case of events without a defined end date. This is manageable by, say, calculating X years into the future, but what happens X years later?
  • A daily reminder job probably runs overnight, and so doesn't need to execute super fast. This means cutting down on its execution time isn't a priority. And the recurrence calculation time is probably going to be negligible anyway; I expect the bottleneck to be the actual email sending. However, if you have a lot of active, old events to consider (by "a lot", I mean billions) and/or your app server is grinding to a halt under load, this may become important.
  • Option 1 saves DB work. I don't mean storage space (although it does use less); that shouldn't matter unless you have a lot (many trillions) of events. I mean that it's less "chatter" back and forth between your app server and the DB, so there's less chance for a dropped connection, concurrency collision, etc. Please note this is incredibly trivial and really doesn't matter either way, unless your production environment has major problems.
Esoteric Screen Name
  • 6,082
  • 4
  • 29
  • 38
  • 1
    I neither can nor will write your feature for you. Try to do it yourself, and if you have a problem, ask another question which includes a description of what went wrong, your code, and your data. – Esoteric Screen Name Jan 27 '15 at 07:51