web-dev-qa-db-fra.com

Comment actualiser automatiquement le cache à l'aide de Google Guava?

J'utilise la bibliothèque Google Guava pour la mise en cache. Pour l'actualisation automatique du cache, nous pouvons procéder comme suit:

cache = CacheBuilder.newBuilder()               
                    .refreshAfterWrite(15, TimeUnit.MINUTES)
                    .maximumSize(100)
                    .build(....);

Cependant, des rafraîchissements automatiques sont effectués lors de la première demande périmée d'une entrée.

Existe-t-il un moyen de le rafraîchir automatiquement même si aucune demande de données de cache n'est venue? Comme toutes les 15 minutes, les données de cache doivent être extraites de Db et chargées, peu importe si quelqu'un appelle ou non les données de cache .

En outre, le délai d'expiration du cache de Guava est pour le cache entier. Est-il possible d'expirer les valeurs du cache en fonction de la clé? Comme les données du cache avec la clé "NOT_SO_FREQ_CHANGE_DATA" expirent toutes les 1 heure et les données avec la clé "FREQ_CHANGING_DATA" devraient expirer toutes les 15 minutes?

30

La goyave ne fournit aucun moyen d'actualiser le cache en bloc, mais vous pouvez planifier vous-même une actualisation périodique:

LoadingCache<K, V> cache = CacheBuilder.newBuilder()
        .refreshAfterWrite(15, TimeUnit.MINUTES)
        .maximumSize(100)
        .build(new MyCacheLoader());

for (K key : cache.asMap().keySet()) {
    cache.refresh(key);
}

Mais dans ce cas, vous souhaiterez peut-être remplacer la méthode CacheLoader.reload(K, V) dans MyCacheLoader afin qu'elle fonctionne de manière asynchrone.

Quant à la deuxième question, non, vous ne pouvez pas définir d'expiration par entrée dans la goyave.

26
Frank Pavageau

Version Java 8 avec flux parallèle:

Executors
        .newSingleThreadScheduledExecutor()
        .scheduleWithFixedDelay(() -> configurationCache
                .asMap()
                .keySet()
                .parallelStream()
                .forEach((key) -> configurationCache.refresh(key)),
            0,
            1, TimeUnit.SECONDS);
6

1ère question. Utilisez un exécuteur planifié pour lancer une actualisation périodique.

2e question. Si vous pouvez déduire votre stratégie d'expiration à partir de votre clé de cache ou de la valeur précédemment mise en cache, il est possible de rafraîchir vos données à des intervalles variables.

sur la base de ceci: https://code.google.com/p/guava-libraries/wiki/CachesExplained#Refresh

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
   .refreshAfterWrite(1, TimeUnit.MINUTES)
   .build(
       new CacheLoader<Key, Graph>() {
         public Graph load(Key key) { // no checked exception
           return getGraphFromDatabase(key);
         }

         public ListenableFuture<Graph> reload(final Key key, Graph prevGraph) {
           if (!needsRefresh(key,prevGraph)) {
             return Futures.immediateFuture(prevGraph);
           } else {
             // asynchronous!
             ListenableFutureTask<Graph> task = ListenableFutureTask.create(new Callable<Graph>() {
               public Graph call() {
                 return getGraphFromDatabase(key);
               }
             });
             executor.execute(task);
             return task;
           }
         }
       });

ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ses.scheduleWithFixedDelay(
    new Runnable() {
        public void run() {
            for (Key key : graphs.asMap().keySet()) {
                graphs.refresh(key);
            }
        }
    }, 0, UPDATE_INTERVAL, TimeUnit.MINUTES);
6
McKidoubled