Redis
 sql >> Database >  >> NoSQL >> Redis

Come disabilitare Redis Caching in fase di esecuzione se la connessione Redis non riesce

Riduciamolo un po'. L'applicazione utilizza la memorizzazione nella cache (implementata con Redis). Se la connessione Redis è obsoleta/chiusa o meno, si desidera che l'applicazione ignori la memorizzazione nella cache e (presumibilmente) vada direttamente a un archivio dati sottostante (ad es. RDBMS). La logica del servizio dell'applicazione potrebbe essere simile a...

@Service
class CustomerService ... {

    @Autowired
    private CustomerRepository customerRepo;

    protected CustomerRepository getCustomerRepo() {
        Assert.notNull(customerRepo, "The CustomerRepository was not initialized!");
        return customerRepo;
    }

    @Cacheable(value = "Customers")
    public Customer getCustomer(Long customerId) {
        return getCustomerRepo().load(customerId);
    }
    ...
}

Tutto ciò che conta nell'astrazione della cache di Spring core per accertare un "mancato" nella cache è che il valore restituito sia nullo. Pertanto, Spring Caching Infrastructure procederà quindi alla chiamata del metodo di servizio effettivo (ad esempio getCustomer). Tieni presente che quando viene restituita la chiamata getCustomerRepo().load(customerId), devi anche gestire il caso in cui Spring's Caching Infrastructure tenta ora di memorizzare nella cache il valore.

Nello spirito di mantenerlo semplice , faremo a meno di AOP, ma dovresti essere in grado di farlo anche usando AOP (a tua scelta).

Tutto ciò di cui hai bisogno è un RedisCacheManager "personalizzato" che estende l'implementazione di SDR CacheManager, qualcosa come...

package example;

import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCacheManager;
...

class MyCustomRedisCacheManager extends RedisCacheManager {

    public MyCustomerRedisCacheManager(RedisTemplate redisTemplate) {
        super(redisTemplate);
    }

    @Override
    public Cache getCache(String name) {
        return new RedisCacheWrapper(super.getCache(name));
    }


    protected static class RedisCacheWrapper implements Cache {

        private final Cache delegate;

        public RedisCacheWrapper(Cache redisCache) {
            Assert.notNull(redisCache, "'delegate' must not be null");
            this.delegate = redisCache;
        }

        @Override
        public Cache.ValueWrapper get(Object key) {
            try {
              delegate.get(key);
            }
            catch (Exception e) {
                return handleErrors(e);
            }
        }

        @Override
        public void put(Object key, Object value) {
            try {
                delegate.put(key, value);
            }
            catch (Exception e) {
                handleErrors(e);
            }
        }

        // implement clear(), evict(key), get(key, type), getName(), getNativeCache(), putIfAbsent(key, value) accordingly (delegating to the delegate).

        protected <T> T handleErrors(Exception e) throws Exception {
            if (e instanceof <some RedisConnection Exception type>) {
                // log the connection problem
                return null;
            }
            else if (<something different>) { // act appropriately }
            ...
            else {
                throw e;
            }
        }
    }
}

Quindi, se Redis non è disponibile, forse il meglio che puoi fare è registrare il problema e procedere per consentire l'invocazione del servizio. Chiaramente, questo ostacolerà le prestazioni, ma almeno aumenterà la consapevolezza dell'esistenza di un problema. Chiaramente, questo potrebbe essere legato a un sistema di notifica più robusto, ma è un esempio grezzo delle possibilità. L'importante è che il tuo Servizio rimanga disponibile mentre gli altri servizi (ad es. Redis) da cui dipende il servizio dell'applicazione potrebbero non funzionare.

In questa implementazione (rispetto alla mia spiegazione precedente) ho scelto di delegare all'implementazione RedisCache sottostante e effettiva per consentire che si verifichi l'eccezione, quindi sapendo perfettamente che esiste un problema con Redis e in modo da poter gestire l'eccezione in modo appropriato. Tuttavia, se si è certi che l'eccezione è correlata a un problema di connessione al momento dell'ispezione, è possibile restituire "null" per consentire a Spring Caching Infrastructure di procedere come se fosse una cache "mancata" (ad es. Connessione Redis errata ==Cache mancante, in questo caso).

So che qualcosa del genere dovrebbe aiutare il tuo problema poiché ho creato un prototipo simile di un'implementazione "personalizzata" di CacheManager per GemFire ​​e uno dei clienti di Pivotal. In quella particolare UC, il "mancato" della cache doveva essere attivato da una "versione non aggiornata" dell'oggetto dominio dell'applicazione in cui la produzione prevedeva un mix di client applicativi più recenti e meno recenti che si connettevano a GemFire ​​tramite l'astrazione della cache di Spring. Ad esempio, i campi dell'oggetto del dominio dell'applicazione cambieranno nelle versioni più recenti dell'app.

Comunque, spero che questo ti aiuti o ti dia altre idee.

Saluti!