sql >> Databáze >  >> NoSQL >> Redis

Jak zakázat ukládání do mezipaměti Redis za běhu, pokud připojení redis selhalo

Pojďme to trochu povařit. Vaše aplikace používá ukládání do mezipaměti (implementované s Redis). Pokud je připojení Redis zastaralé/uzavřené nebo jinak, pak chcete, aby aplikace obešla ukládání do mezipaměti a (pravděpodobně) přešla přímo do základního úložiště dat (např. RDBMS). Logika služby aplikace může vypadat podobně jako...

@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);
    }
    ...
}

Vše, na čem záleží v abstrakci mezipaměti jádra Spring, aby se zjistilo, že mezipaměť chybí, je, že vrácená hodnota je nulová. Jako taková bude Spring Caching Infrastructure pokračovat ve volání skutečné metody služby (tj. getCustomer). Mějte na paměti, že při návratu volání getCustomerRepo().load(customerId) musíte také zvládnout případ, kdy se infrastruktura Spring's Caching Infrastructure nyní pokouší uložit hodnotu do mezipaměti.

V duchu jednoduchosti , obejdeme se bez AOP, ale měli byste být schopni toho dosáhnout také pomocí AOP (vaše volba).

Vše, co byste (měli) potřebovat, je „vlastní“ RedisCacheManager rozšiřující implementaci SDR CacheManager, něco jako...

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;
            }
        }
    }
}

Pokud tedy není Redis k dispozici, možná nejlepší, co můžete udělat, je zaprotokolovat problém a pokračovat, aby došlo k vyvolání služby. Je zřejmé, že to omezí výkon, ale alespoň to zvýší povědomí o tom, že problém existuje. Je zřejmé, že by to mohlo být spojeno s robustnějším systémem oznámení, ale je to hrubý příklad možností. Důležité je, že vaše služba zůstává dostupná, zatímco ostatní služby (např. Redis), na kterých služba aplikace závisí, mohou selhat.

V této implementaci (oproti mému předchozímu vysvětlení) jsem se rozhodl delegovat na základní, skutečnou implementaci RedisCache, abych nechal výjimku nastat, pak jsem dobře věděl, že problém s Redis existuje, a můžete se s výjimkou vhodně vypořádat. Pokud jste si však po kontrole jisti, že výjimka souvisí s problémem s připojením, můžete vrátit „null“, aby infrastruktura Spring Caching Infrastructure pokračovala, jako by to byla chyba mezipaměti (tj. špatné připojení Redis ==Chyba mezipaměti, v tomto případě).

Vím, že něco takového by mělo pomoci vašemu problému, protože jsem vytvořil podobný prototyp „vlastní“ implementace CacheManager pro GemFire ​​a jednoho ze zákazníků společnosti Pivotal. V tomto konkrétním UC muselo být „chybění“ mezipaměti spuštěno „neaktuální verzí“ objektu aplikační domény, kde produkce měla kombinaci novějších a starších aplikačních klientů, kteří se připojovali ke GemFire ​​prostřednictvím Spring's Caching Abstraction. Pole objektů aplikační domény by se například v novějších verzích aplikace změnila.

Každopádně doufám, že vám to pomůže nebo vám dá další nápady.

Na zdraví!



  1. Pohyblivé průměry s agregačním rámcem MongoDB?

  2. Hledejte ve více kolekcích v MongoDB

  3. Vraťte poslední skutečnou hodnotu pro každou skupinu

  4. Jak vytvořit schéma Mongoose s polem ID objektů?