1

I have an entity (model) called Notification, shown to Users of the system. So far, Notifications were created and showed instantly to users when they were enabled, and hidden when disabled or deleted. Also, Users can close/cancel the Notification so they don't see it anymore and that action is persisted in a collection (database table) of Notifications viewed by Users. The system must now implement repetitions of those Notifications, like agendas or calendars in which entries can be repeated daily, weekly, monthly, etc. and also send a email to the User the day before the Notification instance date. Conceptually how it is implemented? How about calculation of repetition?

So far, I've been thinking of persisting three new properties on the Notification entity, one for the type of repetition (daily, weekly, etc.), one for the start date(time) and another for the end date(time) and a new collection (database table) where I save "instances" of those Notifications (not instances like class instance, but a more generic concept of a single occurrence of something), with properties like notification id and start and end date(time) of that instance. That way Notifications themselves wouldn't be presented to Users, but the instances of those Notifications. Then, I thought of a scheduled task (cronjob) that runs couple of times a day, generating instances from Notifications collection calculating when those repetitions should happen and also sending email when calculated instance date is tomorrow.

Not sure if this is the best way and I'd like to hear recommendations. I started to implement it that way and so far it seems easy, but I'm about to start with the logic of the scheduled task (the hardest part) and I wonder if it will be very complex to calculate the date of the instances based on repetition specification (daily seems easy, add a day to the date value, but how about each third friday of the month?).

2 Answers 2

2

This is when separating interface from implementation is important. Your interface should handle third Friday of every month and worse (The 3rd Friday of every month except move to the next business day that both parties to the contract agree is a business day based on the holiday table for the region the business is incorporated under), but you should only have to implement the cases that are real right now.

So I would make a scheduler interface that can be passed a time period, and the scheduler can fill the time period with instances when you tell it to. The logic of how to do that lives inside the scheduler object.

As far as the cron job - you could use this design and have a cron job that creates new instances, but you may find you just don't need it. It might be helpful to do something like the cron job if you need to write a database query against instances and you don't care about the logic of the schedule that created them. If the cron job runs quickly enough you may be able to just trigger the job whenever you need the data to be current, instead of using cron.

6
  • If you're persisting instances of a recurring event what do you do when someone creates an event that starts next week and happens every other Tuesday and is going to continue indefinitely? Commented May 16, 2012 at 17:33
  • 1
    @JohntheRevelator - It may make sense to "blast out" (into individual database records) a bunch of instances out to a certain point in time. Basically this is a kind of caching and might make sense if there are lots of schedules (say, in a big databsae) and the time to compute all the instances is worth avoiding. For a single schedule in isolation it's harder to imagine that being worth it.
    – psr
    Commented May 16, 2012 at 17:38
  • Sorry, I forgot to mention that Users can close/cancel the Notification on the system so they don't see that instance anymore. Also, the system must send a email to the User the day before the notification. That's why I thought of a cronjob. I updated the question with that details. Commented May 16, 2012 at 17:46
  • I'm still thinking about what you said in your answer. I'll keep you updated when I have the application of your answer more clear in my mind. Commented May 16, 2012 at 17:49
  • I'm thinking that pre-filling a time period with instances would be good. The only problem is how many/how much? Do I pre-fill only a month of instances? Thanks also to @JohntheRevelator for helping improve this answer. Commented May 16, 2012 at 18:29
2

I was with you up until the part where you mentioned storing "instances" using a cronjob. Of course every domain has different requirements, but I've found that most often the simplest and most effective way to manage recurring events is to be optimistic and persist variations.

By this I mean you have a recurring event/notification/anything with a start date, end date and frequency. This single entity alone allows you to draw the instances in the UI. The only time you should need to persist instance information is if someone cancels on a specific date, or makes a note for a specific date or whatever. So your recurring event can have collections of cancellations, notes, and other entities for specific dates (instances). This allows you to correctly draw the UI without having a persisted entity for each recurring event instance. Of course you'll need business logic to ensure that your recurring event doesn't have a cancellation or other instance information for a date on which the event will not occur.

Let me know if this makes sense or if you need any other clarification.

EDIT:

I have implemented such features by persisting the "Dismissals" and "Sent Mail" in separate collections for any given event. That is, when a user clicks to dismiss a notification you record in the database that the notification for 5/16/2012 has been read so that you know not to draw it in the UI.

As psr pointed out, doing all these calculations can take a toll on performance. I've found, however, that it's not a problem in any of my programs because databases are very fast and the biggest timespan you're ever looking at is usually a month or a few months. Also, I think it keeps your model much cleaner because you don't have to worry about creating and destroying instances in the database all the time in the cases where an event will recur indefinitely or the user changes the start and end dates.

That said, you will need a scheduled task to to send out the emails regularly. The task can look to see what events are coming up and which ones have emails that have already been sent out to figure out what emails to send.

3
  • Sorry, I forgot to mention that Users can close/cancel the Notification on the system so they don't see that instance anymore. Also, the system must send a email to the User the day before the notification. That's why I thought of a cronjob. I updated the question with that details. Commented May 16, 2012 at 17:39
  • @AlejandroGarcíaIglesias see my edit. Commented May 16, 2012 at 17:48
  • Your answer made me think a bit more on the problem. I already have a database table for dismissals, but will need to change it on a per instance instead of per Notification. Regarding emails, I can pre-fill a email queue with desired sending dates in the same process that I pre-fill the instances. Commented May 16, 2012 at 18:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.