views:

38

answers:

1

I have a JSP that will take some 8 minutes to render. The code logic itself can not be made more efficient (it will update often and be updated by basically a pointy haired boss). I tried wrapping it with a caching layer like

<%@ taglib uri="/WEB-INF/classes/oscache.tld" prefix="oscache" %>
<oscache:cache time="60">
  <div class="pagecontent">
  ..... my logic
  </div>
</oscache:cache>

This is nice until the 60 seconds is over. The next query after that blocks until the 8 minutes of rendering is done with again. I would need a way to build a pattern something like:

  1. If there is no version of the dynamic content in the cache run the actual logic (and populate the cache for subsequent requests)
  2. If there is a non-expired version of the dynamic content in the cache serve the output of the JSP logic from the cache
  3. If there is an expired version of the dynamic content in the cache serve the output of the JSP logic still from the cache AND run the JSP logic in the background so that the cache gets updated transparently to the user - avoiding the user have to wait for 8 minutes

I found out that at least EHCache might be able to do some asynchronous cache updating but it did not sadly seem to apply to the JSP tags... Also I have to take in 10-20 parameters for the actual logic of the JSP and some of them should be used as a key for caching.

Code example and/or pointers would be greatly appreciated. I do not frankly care if the solution provided is extremely ugly. I just want a simple 5 minute caching with asynchronous cache update taking into account some parameters as a key.

+1  A: 

If your cached data is common across all users, using JSTL application scope allows you to cache your JSP fragment. If it per user, then session scope.

Along with that, use another variable to record the cache-refresh timestamp, or conversely an expiry time. An example below:

<c:if test="${empty cachedData}">
<c:set var="cachedData" scope="application">
<%-- Cached JSP content goes here -->
</c:set>
<c:set var="cachedRefreshTimestamp"
  value="<%= new Long(new java.util.Date().getTime()) %>"
  scope="application"/>
</c:if>

Later:

If (system current time + 5) > cachedRefreshTimestamp, go fetch data again in separate loop, overwrite back into cachedData, and update cachedRefreshTimestamp also

JoseK