sql >> Databasteknik >  >> NoSQL >> Redis

Hur man inaktiverar Redis Caching vid körning om redis-anslutningen misslyckades

Låt oss koka ner det här lite. Din applikation använder caching (implementerad med Redis). Om Redis-anslutningen är inaktuell/stängd eller på annat sätt, vill du att applikationen ska kringgå cachning och (förmodligen) gå direkt till ett underliggande datalager (t.ex. RDBMS). Programtjänstens logik kan se ut som...

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

Allt som spelar någon roll i Spring cores Caching Abstraktion för att fastställa en Cache "miss" är att värdet som returneras är null. Som sådan kommer Spring Caching Infrastructure sedan fortsätta med att anropa den faktiska tjänstemetoden (dvs getCustomer). Tänk på att när anropet getCustomerRepo().load(customerId) returneras, måste du också hantera fallet där Springs Caching Infrastructure nu försöker cache värdet.

I andan att hålla det enkelt , vi klarar oss utan AOP, men du bör också kunna uppnå detta med AOP (ditt val).

Allt du (borde) behöver är en "anpassad" RedisCacheManager som utökar implementeringen av SDR CacheManager, något i stil med...

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

Så, om Redis är otillgängligt, kanske det bästa du kan göra är att logga problemet och fortsätta för att låta tjänstanropet ske. Det är klart att detta kommer att hämma prestanda men åtminstone kommer det att öka medvetenheten om att det finns ett problem. Det är klart att detta skulle kunna kopplas till ett mer robust meddelandesystem, men det är ett grovt exempel på möjligheterna. Det viktiga är att din tjänst förblir tillgänglig medan de andra tjänsterna (t.ex. Redis) som applikationstjänsten är beroende av kan ha misslyckats.

I den här implementeringen (i förhållande till min tidigare förklaring) valde jag att delegera till den underliggande, faktiska RedisCache-implementeringen för att låta undantaget inträffa, då jag väl vet att det finns ett problem med Redis och så att du kan hantera undantaget på rätt sätt. Men om du är säker på att undantaget är relaterat till ett anslutningsproblem vid inspektion, kan du returnera "null" för att låta Spring Caching Infrastructure fortsätta som om det vore en Cache "miss" (dvs dålig Redis Connection ==Cache miss, i det här fallet).

Jag vet att något sådant här borde hjälpa ditt problem eftersom jag byggde en liknande prototyp av en "anpassad" CacheManager-implementering för GemFire ​​och en av Pivotals kunder. I just den UC var "missen" för cache tvungen att utlösas av en "föråldrad version" av applikationsdomänobjektet där produktionen hade en blandning av nyare och äldre applikationsklienter som ansluter till GemFire ​​genom Springs Caching Abstraction. Applikationsdomänens objektfält skulle till exempel ändras i nyare versioner av appen.

Hur som helst, hoppas att detta hjälper eller ger dig fler idéer.

Skål!



  1. Redis scan count:Hur tvingar man SCAN att returnera alla nycklar som matchar ett mönster?

  2. Hur löser man ClassNotFoundException:com.mongodb.connection.BufferProvider?

  3. Autokomplettera med java, Redis, Elastic Search, Mongo

  4. MongoDB $trunc