views:

2174

answers:

11

If you were tasked to build an event scheduling system that supported recurring events, how would you do it? How do you handle when an recurring event is removed? How could you see when the future events will happen?

i.e. When creating an event, you could pick "repeating daily" (or weekly, yearly, etc).

One design per response please. I'm used to Ruby/Rails, but use whatever you want to express the design.

I was asked this at an interview, and couldn't come up with a really good response that I liked.

Note: was already asked/answered here. But I was hoping to get some more practical details, as detailed below:

  • If it was necessary to be able to comment or otherwise add data to just one instance of the recurring event, how would that work?
  • How would event changes and deletions work?
  • How do you calculate when future events happen?
+5  A: 

Martin Fowler wrote an article about is. See http://martinfowler.com/apsupp/recurring.pdf

Lars Truijens
I saw that, and it explains how to write code (set expressions) to represent reoccurring events. But it didn't give me much practical insight on how to build a webapp in my system, or how to answer the question at an interview.
Joe Van Dyk
A: 

When saving the event I would save the schedule to a store (let's call it "Schedules" and I'd calculate when the event was to fire the next time and save that as well, for instance in "Events". Then I'd look in "Events" and figure out when the next event was to take place and go to sleep until then.

When the app "wakes up" it would calculate when the event should take place again, store this in "Events" again and then perform the event.

Repeat.

If an event is created while sleeping the sleep is interrupted and recalculated.

If the app is starting or recovering from a sleep event or similar, check "Events" for passed events and act accordingly (depending on what you want to do with missed events).

Something like this would be flexible and would not take unnecessary CPU cycles.

henriksen
Could you look in the future and see when the upcoming events would be?
Joe Van Dyk
+2  A: 

Are you looking for "What's the best way to model recurring events in a calendar application?"

bdukes
A: 

I've had to do this before when I was managing the database end of the project. I requested that each event be stored as separate events. This allows you to remove just one occurrence or you could move a span. It's a lot easier to remove multiples than to try and modify a single occurrence and turn it into two. We were then able to make another table which simply had a recurrenceID which contained the information of the recurrence.

Joe Philllips
A: 

Off the top of my head (after revising a couple things while typing/thinking):

Determine the minimum recurrence-resolution needed; that's how often the app runs. Maybe it's daily, maybe every five minutes.

For each recurring event, store the most recent run time, the run-interval and other goodies like expiration time if that's desirable.

Every time the app runs, it checks all events, comparing (today/now + recurrenceResolution) to (recentRunTime + runInterval) and if they coincide, fire the event.

clweeks
A: 

@Joe Van Dyk asked: "Could you look in the future and see when the upcoming events would be?"

If you wanted to see/display the next n occurences of an event they would have to either a) be calculated in advance and stored somewhere or b) be calculated on the fly and displayed. This would be the same for any evening framework.

The disadvantage with a) is that you have to put a limit on it somewhere and after that you have to use b). Easier just to use b) to begin with.

The scheduling system does not need this information, it just needs to know when the next event is.

henriksen
Or mix the two. Calculate on-demand (b), then store the results for later reference (a).
Dave Sherohman
A: 

A quickie -

  1. I would first design a constant frequency timer that provides a dependable constant ticks every 1 sec / 10 micro sec or whatever minimum possible frequency you require.

  2. The above timer must have be able to take any no of tasks and invoke them at every tick

  3. Each action would have a counter that keeps track of how many ticks it should recieve for it to be activated. So for eg if there is an action that needs to get invoked every 10 secs then after each tick the counter gets incremented and gets reset to 0 when it reaches 10. At this point the command contained in the action shall run

  4. Design higher granularity ticks like seconds and minutes for the lower granularity tick.

  5. Design further high granularity action like Hour that is loaded as actions for the minute timer

  6. Days and Months would be actions for the hour timer

  7. External actions should be loaded into the appropriate predefined action based on their recurrence property.

  8. Actions can easily support interfaces that allows them to unhook from their parent action / calculate how many ticks are already received and report how many to go etc.

sounds like decorator pattern could be made use of here ?

A: 

When I wrote a calendar app for myself mumble years ago, I basically just stole the scheduling mechanism from cron and used that for recurring events. e.g., Something taking place on the second Saturday of every month except January would include the instruction "repeat=* 2-12 8-14 6" (every year, months 2-12, the 2nd week runs from the 8th to the 14th, and 6 for Saturday because I used 0-based numbering for the days of the week).

While this makes it quite easy to determine whether the event occurs on any given date, it is not capable of handling "every N days" recurrence and is also rather less than intuitive for users who aren't unix-savvy.

To deal with unique data for individual event instances and removal/rescheduling, I just kept track of how far out events had been calculated for and stored the resulting events in the database, where they could then be modified, moved, or deleted without affecting the original recurrent event information. When a new recurring event was added, all instances were immediately calculated out until the existing "last calculated" date.

I make no claim that this is the best way to do it, but it is a way, and one which works quite well within the limitations I mentioned earlier.

Dave Sherohman
A: 

If you have a simple reoccuring event, such as daily, weekly or a couple days a week, whats wrong with using buildt in scheduler/cron/at functionallity? Creating an executable/console app and set up when to run it? No complicated calendar, event or time management.

:)

//W

superwiren
doesn't work for a web application
Joe Van Dyk
+1  A: 

I started by implementing some temporal expression as outlined by Martin Fowler. This takes care of figuring out when a scheduled item should actually occur. It is a very elegant way of doing it. What I ended up with was just a build up on what is in the article.

The next problem was figuring out how in the world to store the expressions. The other issue is when you read out the expression, how do those fit into a not so dynamic user interface? There was talk of just serializing the expressions into a BLOB, but it would be difficult to walk the expression tree to know what was meant by it.

The solution (in my case) is to store parameters that fit the limited number of cases the User Interface will support, and from there, use that information to generate the Temporal Expressions on the fly (could serialize when created for optimization). So, the Schedule class ends up having several parameters like offset, start date, end date, day of week, and so on... and from that you can generate the Temporal Expressions to do the hard work.

As for having instances of the tasks, there is a 'service' that generates tasks for N days. Since this is an integration to an existing system and all instances are needed, this makes sense. However, an API like this can easily be used to project the recurrences without storing all instances.

Greg Ogle