Перехватчик Spring Cache

Существует система, на которую мы полагаемся, чтобы предоставлять информацию, которая довольно часто выходит из строя. В настоящее время мы используем hazelcast для кэширования записей с истечением срока действия в 1 час. Однако у этого есть проблема, заключающаяся в том, что записи в кеше удаляются вслепую, поэтому, если система недоступна, запросы на некоторое время не будут выполняться.

Я ищу способ перехватить кеш весны, чтобы добавить логику, грубо говоря, я пытаюсь изменить внутренний вызов весны из

Object valueFromCache = cache.getValue(cacheKey);
if (null == valueFromCache) {
    valueFromCache = cachedMethod.invokeMethod();
    cache.putValue(cacheKey, valueFromCache);
}
return valueFromCache;

to

Object valueFromCache = cache.getValue(cacheKey);
if (null == valueFromCache) {
    valueFromCache = cachedMethod.invokeMethod();
    cache.putValue(cacheKey, valueFromCache);
} else if (isValueExpired(valueFromCache)) {
    try {
        valueFromCache = cacheMethod.invokeMethod();
        cache.putValue(cacheKey, valueFromCache);
    } catch (FailedToRefreshDataException ex) {
        doWhateverWithException(ex);
    }
}
return valueFromCache;

По сути, я не хочу, чтобы базовый поставщик кеша (в моем случае hazelcast) решал, когда удалять записи, а только приложение в случае, когда было получено более новое значение.

Мы можем справиться с риском наличия немного устаревших данных, чтобы повысить доступность.

РЕДАКТИРОВАТЬ: я хочу, чтобы что-то вело себя так же, как RefreAfterWrite гуавского кеш-построителя.

Например

public static void main(String[] args) throws ExecutionException, InterruptedException {
    AtomicInteger atomicInteger = new AtomicInteger();
    LoadingCache<String, String> cache = CacheBuilder.newBuilder()
            .refreshAfterWrite(100, MILLISECONDS)
            .build(new CacheLoader<String, String>() {
                @Override
                public String load(String value) throws Exception {
                    int intValue = atomicInteger.incrementAndGet();
                    if (intValue % 2 == 0) {
                        throw new IllegalStateException("Failed to whatever");
                    }
                    return value + intValue;
                }
            });

    for (int i = 0; i < 10; i++) {
        System.out.println("Attempt " + i + "=" + cache.get("Shoes"));
        Thread.sleep(50);
    }
}

выходы

Attempt 0=Shoes1
Attempt 1=Shoes1
Attempt 2=Shoes1
Attempt 3=Shoes3
Attempt 4=Shoes3
Attempt 5=Shoes3
Attempt 6=Shoes5
Attempt 7=Shoes5
Attempt 8=Shoes5
Attempt 9=Shoes7

Не удалось выполнить выборку кеша, так как эталонная система была недоступна.


person Alexandru    schedule 24.09.2017    source источник


Ответы (1)


Если вам нужно refreshAfterWrite для Hazelcast, это time-to-live-seconds.

time-to-live-seconds изменяется только тогда, когда вы выполняете операцию map.put, так что это в основном то же самое, что и настройка refreshAfterWrite в Guava.

См.: http://docs.hazelcast.org/docs/3.8.6/manual/html-single/index.html#map-eviction

Кроме того, вы, скорее всего, захотите обновить данные в кеше после истечения срока действия. Затем вы можете использовать MapLoader или интерфейс. (http://docs.hazelcast.org/docs/3.8.6/manual/html-single/index.html#loading-and-storing-persistent-data)

Таким образом, когда срок действия данных истечет, следующий вызов вызовет метод MapLoader.load, и там вы сможете проверить/получить новые данные из любого источника.

person Gokhan Oner    schedule 27.09.2017
comment
время жизни в секундах - это не то, что я ищу, как указано в самом первом предложении описания моей проблемы. Я не хочу, чтобы записи удалялись вслепую, я хочу, чтобы они заменялись только в том случае, если доступна новая версия. - person Alexandru; 29.09.2017
comment
@Alexandru Я только что обновил свой ответ MapLoader, который похож на Guava CacheLoader, но с большим количеством опций. - person Gokhan Oner; 29.09.2017