Guava Cache - InvalidCacheLoadException on refresh


Guava Cache - InvalidCacheLoadException on refresh



I have created a cache using CacheBuilder.
I have used ExpireAfterWrite and RefreshAfterWrite. I have overrided cacheloader load and reload function. Practically in reload I am calling load by creating ListenableFutureTask and submitting it to ExecutorService.
Below is stack trace I am getting -



WARNING: Exception thrown during refresh
[junit] com.google.common.cache.CacheLoader$InvalidCacheLoadException:
CacheLoader returned null for key abc.
[junit] at com.google.common.cache.LocalCache$Segment.getAndRecordStats(Unknown
Source)
[junit] at com.google.common.cache.LocalCache$Segment$1.run(Unknown Source)
[junit] at com.google.common.util.concurrent.MoreExecutors$DirectExecutor.execute(Unknown
Source)
[junit] at com.google.common.util.concurrent.ImmediateFuture.addListener(Unknown
Source)
[junit] at com.google.common.cache.LocalCache$Segment.loadAsync(Unknown Source)
[junit] at com.google.common.cache.LocalCache$Segment.refresh(Unknown Source)
[junit] at com.google.common.cache.LocalCache$Segment.scheduleRefresh(Unknown
Source)
[junit] at com.google.common.cache.LocalCache$Segment.get(Unknown Source)
[junit] at com.google.common.cache.LocalCache.get(Unknown Source)
[junit] at com.google.common.cache.LocalCache.getOrLoad(Unknown Source)



I don't know why its not able to refresh, also It doesn't get to cacheloader.load also. It return null before. I am pretty sure I am not returning null in load function.



Sample 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);


}
}







Please, provide your project and test config
– Pospolita Nikita
Jun 29 at 6:50





Cache = new Cache(simpleCacheLoader, CACHE_MAX_SIZE, // 1000 CACHE_EXPIRE_TIME, // 10 CACHE_REFRESH_TIME, // 2 CACHE_CONCURRENCY_LEVEL, 4 new FakeTicker);
– user3671657
Jun 29 at 6:54





simpleCacheLoader "returned null for key abc".
– Xaerxess
Jun 29 at 7:21


simpleCacheLoader





provide test code, provide method call and method full code, format your code, update post. I can't help you if I don't see anything
– Pospolita Nikita
Jun 29 at 7:27





@PospolitaNikita I will update it later. And will tag you again.
– user3671657
Jun 29 at 7:28




1 Answer
1



So it was @ mock at SimpleCacheLoader in test file which was not doing anything on refresh as I didn't stub the method. I should have used @ spy in this case. I got it fixed. Thanks for help everyone.






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Comments

Popular posts from this blog

paramiko-expect timeout is happening after executing the command

Export result set on Dbeaver to CSV

Opening a url is failing in Swift