Guava Cache - InvalidCacheLoadException при обновлении - PullRequest
0 голосов
/ 29 июня 2018

Я создал кеш с помощью 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 $ Сегмент $ 1.run (неизвестный источник) [junit] на com.google.common.util.concurrent.MoreExecutors $ DirectExecutor.execute (Неизвестно Источник) [junit] на com.google.common.util.concurrent.ImmediateFuture.addListener (Неизвестно Источник) [junit] at com.google.common.cache.LocalCache $ Segment.loadAsync (неизвестный источник) [junit] at 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] at com.google.common.cache.LocalCache.getOrLoad (неизвестный источник)

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

Пример кода -

</p> <pre><code>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 Ответ

0 голосов
/ 02 июля 2018

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

...