Guava Cache - InvalidCacheLoadException при обновлении

Я создал кеш с помощью CacheBuilder. Я использовал ExpireAfterWrite и RefreshAfterWrite. Я переопределил функцию загрузки и перезагрузки кеш-загрузчика. Практически при перезагрузке я вызываю load, создавая ListenableFutureTask и отправляя его в ExecutorService. Ниже приведена трассировка стека, которую я получаю -

ВНИМАНИЕ: Исключение выдается во время обновления [junit] com.google.common.cache.CacheLoader$InvalidCacheLoadException: CacheLoader вернул ноль для ключа abc. [junit] на com.google.common.cache.LocalCache$Segment.getAndRecordStats(неизвестный источник) [junit] на com.google.common.cache.LocalCache$Segment$1.run(неизвестный источник) [junit] на com.google.common.util.concurrent.MoreExecutors$DirectExecutor.execute(Неизвестный источник) [junit] в com.google.common.util.concurrent.ImmediateFuture.addListener(Неизвестный источник) [junit] в com.google.common.cache.LocalCache$Segment.loadAsync(неизвестный источник) [junit] на com.google.common.cache.LocalCache$Segment.refresh(неизвестный источник) [junit] на com.google.common.cache.LocalCache$Segment.scheduleRefresh(неизвестный источник) [junit] на com.google.common.cache.LocalCache$Segment.get(неизвестный источник) [junit] на com.google.common.cache.LocalCache.get(неизвестный источник) [junit] на com.google.common.cache.LocalCache.getOrLoad(Неизвестный источник)

Я не знаю, почему он не может обновиться, он также не попадает в cacheloader.load. Он возвращает ноль раньше. Я уверен, что я не возвращаю ноль в функции загрузки.

Образец кода -

public class SampleCacheLoader extends CacheLoader<String, Customer> {

    private final DatabaseClient databaseClient;

    private static final ExecutorService ex  = Executors.newSingleThreadScheduledExecutor();

    @Inject
    public SampleCacheLoader(final DatabaseClient databaseClient) {
        this.databaseClient = databaseClient;
    }

    @Override
    public Customer load(final String customerId) throws Exception {
        Customer customer = databaseClient.getCustomer(customerId);
        if (customer == null) {
            throw new Exception("Customer is null");
        }
        return customer;
    }

@Override
public ListenableFuture<Customer> reload(final String customerId,
                                                     final Customer prevCustomer)
        throws Exception {
    ListenableFutureTask<Customer> task = ListenableFutureTask
            .create(new Callable<Customer>() {

        @Override
        public Customer call() {
            try {
                // try to get a new value
                load(customerId);

            } catch (Throwable e) {
                // or return the old one in the event of failure
                return prevCustomer;
            }
        }
    });

    // run in the background so that concurrent get() requests still return values.
    ex.execute(task);
    return task;
}
}

public class SampleCache {

    public  LoadingCache<String, Customer> sampleCache;

    @Inject
    public SampleCache(final SampleCacheLoader sampleCacheLoader,
                                         final int cacheMaxSize,
                                         final int cacheExpireTime,
                                         final int cacheRefreshTime,
                                         final int concurrencryLevel,
                                         final Ticker ticker) {
        this.cache = CacheBuilder.newBuilder()
                .maximumSize(cacheMaxSize)
                .expireAfterWrite(cacheExpireTime, TimeUnit.MINUTES)
                .refreshAfterWrite(cacheRefreshTime, TimeUnit.MINUTES)
                .concurrencyLevel(concurrencryLevel)
                .ticker(ticker)
                .build(sampleCacheLoader);
    }

    public Optional<Customer> get(final String customerId) {
        try {
            Customer customer = cache.get(customerId);
            return Optional.of(customer);
        } catch (ExecutionException e) {
            log.warn(String.format("failed to get customer from cache (customerId=%s)", customerId));
            log.warn(e.getMessage());
        }

        return Optional.empty();
    }

    /**
     * Size of customer cache.
     * @return size of customer cache.
     */
    public long size() {
        return  cache.size();
    }

}

public class Customer {

   private String name;
}

public class SampleCacheTest extends TestCase {

    SampleCache SampleCache;

    SampleCacheLoader SampleCacheLoader;

    // FakeTicker to test cache expiry.
    FakeTicker ft;

    // Max size of cache
    final  int CACHE_MAX_SIZE = 1000;

    // CACHE_EXPIRE_TIME is in minutes.
    final int CACHE_EXPIRE_TIME = 1000;

    // CACHE_REFRESH_TIME is in minutes.
    final int CACHE_REFRESH_TIME = 3;

    // CACHE_CONCURRENCY_LEVEL.
    final int CACHE_CONCURRENCY_LEVEL = 10;

    // Resource arn
    final Static String CUSTOMER_ID =
            "abc";

    @Before
    public void setUp() throws Exception {
        // FaceTicker provided by google source code.
        ft = new FakeTicker();
        SampleCacheLoader sampleCacheLoader = new sampleCacheLoader(new DatabaseClient());
        SampleCache = new SampleCache(sampleCacheLoader,
                CACHE_MAX_SIZE,
                CACHE_EXPIRE_TIME,
                CACHE_REFRESH_TIME,
                CACHE_CONCURRENCY_LEVEL,
                ft);
    }

    @Test
    public void testCacheRefreshTime() throws Exception {

        Optional<Customer> customer1 = SampleCache.get(CUSTOMER_ID);
        assertTrue(customer1.isPresent());
        assertNotNull(customer1.get());

        // Advancing time by 1 minutes and retrieve it from cache
        // So that it won't expire. Gets the old entry.
        advanceTimeForCache(1);

        Optional<Customer> customer2 = SampleCache.get(CUSTOMER_ID);
        assertTrue(customer2.isPresent());
        assertNotNull(customer2.get());

        // After this any get call for CUSTOMER_ID
        // should initiate the refresh and Load.
        // new value from db.
        advanceTimeForCache(4);

        // This is the place where I get CacheInvalidateStateException
        Optional<Customer> customer3 = SampleCache.get(CUSTOMER_ID);


    }
}

1 ответ

Таким образом, это было @ mock в SimpleCacheLoader в тестовом файле, который ничего не делал при обновлении, так как я не заглушал метод. Я должен был использовать @ шпион в этом случае. Я исправил это. Спасибо за помощь всем.

Другие вопросы по тегам