0

I asked a question a while back on here regarding caching data for a calendar/scheduling web app, and got some good responses. However, I have now decided to change my approach and stat caching the data in javascript.

I am directly caching the HTML for each day's column in the calendar grid inside the $('body').data() object, which gives very fast page load times (almost unnoticable).

However, problems start to arise when the user requests data that is not yet in the cache. This data is created by the server using an ajax call, so it's asynchronous, and takes about 0.2s per week's data.

My current approach is simply to block for 0.5s when the user requests information from the server, and cache 4 weeks either side in the inital page load (and 1 extra week per page change request), however I doubt this is the optimal method.

Does anyone have a suggestion as to how to improve the situation?

To summarise:

  • Each week takes 0.2s to retrieve from the server, asynchronously.
  • Performance must be as close to real-time as possible. (however the data is not needed to be fully real-time: most appointments are added by the user and so we can re-cache after this)
  • Currently 4 weeks are cached on either side of the inial week loaded: this is not enough.
  • to cache 1 year takes ~ 21s, this is too slow for an initial load.

6
  • 1
    This may be OT and is not intended to be sarky in any way: Is there anything you can do about the server-side times? I'm surprised that you get a week back in ~0.2s, but two weeks takes ~0.4s. I would have expected with most backends that two weeks would take almost exactly as much time as one week with most of that time being setting up the request, checking a connection out of a DB pool or whatever, etc., etc., rather than the actual query. But again, this is probably OT and is certainly based in ignorance of your infrastructure. :-) Commented Mar 15, 2010 at 13:04
  • Yes, I think more information is needed about what you're doing on the server. Where is your slowdown? Typically it's in the DB, of course, but maybe it's something else. Commented Mar 15, 2010 at 13:13
  • No, that's a fair comment: I actually took out the transfer times (it's closer to 0.5 with them included): I'd not like to count on the transfer speeds: this is running in my local ASP.net dev environment (in debug) at the moment, so there's no guarantee that they will be the same once they're on the live server, especially since the live setup is load balanced, and so has variable performance due to routing etc. The 20s figure for one year is with transfers included. I'd think of it more that 1 week takes ~ 0.2 seconds to turn into HTML from the data source. Commented Mar 15, 2010 at 13:15
  • @WVDominick the data comes straight from the database: there's not really a way to pre-cache it. There's also the overhead from creating the html, it's surprisingly hard to get the appointments to line up properly etc. when you can have multiple concurrent appointments, and this leads to a rather horrific O(nlogn) function being called once per output day. Commented Mar 15, 2010 at 13:18
  • This sounds complex and CPU heavy, I'd be tempted to defer to GCal over API :) Commented Mar 15, 2010 at 13:50

1 Answer 1

2

As I read your description, I thought of 2 things: Asynchrony and Caching.

First, Asynchrony

Why would you block for 0.5s? Why not use an ajax call, and in the callback, update the page with the retrieved info. There is no blocking for a set time, it is done asynchronously. You'd have to suppress multiple clicks though, while a request is outstanding, but that shouldn't be a problem at all.

You can also pre-load the in-page cache in the background, using setInterval or better, setTimeout. Especially makes sense if the cost to compute or generate the calendar is long and the data size is relatively small - in other words, small enough to store months in the in-page cache even if it is never used. Sounds like you may be doing this anyway and only need to block when the user jumps out of the range of cached data.

Intelligent Caching

I am imagining the callback function - the one that is called when the ajax call completes - will check if the currently selected date is on the "edge" of the cached data - either the first week in cache or the last week (or whatever). If the user is on the edge, then the callback can send out an additional request to optimistically pre-load the cache up to the 4 week limit, or whatever time range makes sense for your 80% use cases.

You may also consider caching the generated calendar data on the server side, on a per-user basis. If it is CPU- and time-intensive to generate these things, then it should be a good trade to generate once and keep it in the server-side cache, invalidating only when the user makes an update. With x64 servers and cheap memory, this is probably very feasible. Depending on the use cases, it may make for a much more usable interaction, the 2nd time a user connects to the app. You could even consider pre-loading the server-side cache on a per-user basis, before the user requests any calendar.

Sign up to request clarification or add additional context in comments.

5 Comments

Asynchrony: Yep, I'm actually using the callbacks from the page methods to re-call the caching, it seems to work ok. I'm blocking using an UpdatePanel as it's easier to ensure the user cannot click on anything while the request posts, and guarantees a quick turnaround for that week. As for intelligent caching, it is hard to deal with the situation of the user trying to naviagate to a particular week by clicking on the 'next' button repeatedly, as there's not quite enough time to do the check and get the data back.
As for Server-side caching, it's not really feasible in a group environment, it's quite possible to have another user change their appointments while they're logged off, or even while they're logged on. If it's pure client-side, they get refreshed when they load the page again, which ensures the data will always be reasonably fresh.
About the "not enough time" problem. . . There are ways to handle it intelligently. One way is to introduce a delay, via setTimeout, between the click and the resulting ajax call. If an additional click happens before the delay expires, then reset the timer and wait some more. You can assume that multiple Next clicks will occur within 650ms of each other (for example), so if you get three clicks in a row, followed by a delay of more than 650ms, you know to request 3 weeks hence, rather than "this week", "next week" and "the week following" with 3 separate ajax calls.
I disagree it's not feasible in a group environment. You're looking for a distributed memory cache (DMC) look at Memcache, Velocity and similar. At point where you've reached scalability issues and you have a load balanced environment your next step should always be a DMC system after you've verified through profiling that you've reasonably made all the performance increases possible from code execution.
I agree with Marisic; there's no logistical obstacle to prevent you from using server-side caching. A distributed memory cache will scale well across a farm. Also, you can do cache validation checks before using the contents of the cache, to avoid the problem where the backing store has been changed by a different application. On the other hand, I understand that it might not be practical for you to do this.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.