Java – Forcing Cache Refresh

cachingdesignjava

Over View of Application

I'm updating an existing tomcat web application to read certain resources from a REST API. Currently the application reads them from flat files. Since the application is very critical, I added a caching layer so that the objects returned by REST API are always available.

In the service layer of API client, if the request item is not found in the Cache, the request will be sent to the actual API, the response is put in MapDB cache and returned to caller. The startup listener calls a bunch of APIs with different parameters so that all data is now in MapDB cache. I do not set a expiration on the items in cache because I want them to always available unless I refresh on demand.

The problem is Web App and API client are different projects. Since API client decides to read from Cache or API, I'm not able to force refresh cache value from the application.

  • Should I add another parameter to function calls I make to API client or

    Object obj = ServiceFactory.getLanguageService()
                        .getLanguagesFromApi(env.getName(),
                                env.getEnvironmentType(),
                                env.getPhase().toString(), null, true);
    

The last "true" parameter indicates forcing cache refresh.

  • Should I get the existing value in cache to a temporary variable, delete the entry, make API call, if no value is returned because of some error, put the entry back into the cache.

            String key = ClientUtils.concatenateList(
                    Arrays.asList(ClientConstants.RESOURCE_LANGUAGE,
                            env.getName(), env.getEnvironmentType(),
                            env.getPhase(), null),
                    ClientConstants.CACHE_KEY_SEPERATOR,
                    ClientConstants.NULL_STRING);
    
            Object cachedElement = ClientCache.getCache().get(key);
            if (cachedElement != null) {
                ClientCache.getCache().delete(key);
            }
    
            Object obj = ServiceFactory.getLanguageService()
                    .getLanguagesFromApi(env.getName(),
                            env.getEnvironmentType(),
                            env.getPhase().toString(), null);
    
            if (obj == null) {
                ClientCache.getCache().put(key, cachedElement);
            }
    

What is the cleaner way to do this ? I feel adding parameters about caching to function makes it clumsy and add dependencies – like getUsers(String country, boolean forceAPIrequest). But deleting and adding same entries may also waste resources and heap space, causing GC over time. Also, App will directly access Client Cache to do these operations.

All this is based on strong assumption that our REST API is unreliable. Web App should not have any down time.

Best Answer

If I understand correctly, caching is in place mainly for realiability in case of unavailability of REST service, not for performance.

In that case, you could call REST service every time you receive request from the client, if you get a response (REST service is working) you update the MapDB cache and return the response to API client. If REST service is down and you don't get the response, simply return cached value from MapDB.

This way your clients get always as up-to-date possible version as possible while keeping the reliability requirement.

You could include a flag in the response to your clients indicating whether the response is from cache or up-to-date. This might be useful for clients which absolutely require up-to-date response to the point that it is preferable to fail than to work with old data.

Related Topic