@Test public void testGettingImmediateFailure() { AsyncLoadingCache<Integer, Boolean> cachedResult = new AsyncLoadingCache<>(30000); final AtomicInteger callCount = new AtomicInteger(); final Supplier<CompletableFuture<Boolean>> supplier = () -> { int count = callCount.getAndIncrement(); if (count == 0) { CompletableFuture<Boolean> future = new CompletableFuture<>(); RecordCoreException e = new RecordCoreException("this is only a test"); future.completeExceptionally(e); return future; } return CompletableFuture.completedFuture(true); }; try { cachedResult.orElseGet(1, supplier).join(); fail("should throw exception"); } catch (CompletionException ex) { assertThat("we got the expected exception", ex.getCause(), is(instanceOf(RecordCoreException.class))); assertThat("it's the test exception", ex.getCause().getMessage(), containsString("this is only a test")); } assertThat("before future is ready we return the in progress cached future", callCount.get(), is(1)); cachedResult.orElseGet(1, supplier).join(); assertThat("after cached future completes exceptionally we attempt to get the value again", callCount.get(), is(2)); }
@SuppressWarnings("squid:S2789") @Nonnull public CompletableFuture<V> orElseGet(@Nonnull K key, @Nonnull Supplier<CompletableFuture<V>> supplier) { try { Optional<V> cachedValue = cache.getIfPresent(key); if (cachedValue == null) { return MoreAsyncUtil.getWithDeadline(deadlineTimeMillis, supplier).thenApply(value -> { final Optional<V> existingValue = cache.asMap().putIfAbsent(key, Optional.ofNullable(value)); return existingValue == null ? value : existingValue.orElse(null); }); } else { return CompletableFuture.completedFuture(cachedValue.orElse(null)); } } catch (Exception e) { throw new RecordCoreException("failed getting value", e).addLogInfo("cacheKey", key); } }
AsyncLoadingCache { @SuppressWarnings("squid:S2789") @Nonnull public CompletableFuture<V> orElseGet(@Nonnull K key, @Nonnull Supplier<CompletableFuture<V>> supplier) { try { Optional<V> cachedValue = cache.getIfPresent(key); if (cachedValue == null) { return MoreAsyncUtil.getWithDeadline(deadlineTimeMillis, supplier).thenApply(value -> { final Optional<V> existingValue = cache.asMap().putIfAbsent(key, Optional.ofNullable(value)); return existingValue == null ? value : existingValue.orElse(null); }); } else { return CompletableFuture.completedFuture(cachedValue.orElse(null)); } } catch (Exception e) { throw new RecordCoreException("failed getting value", e).addLogInfo("cacheKey", key); } } }
AsyncLoadingCache { @SuppressWarnings("squid:S2789") @Nonnull public CompletableFuture<V> orElseGet(@Nonnull K key, @Nonnull Supplier<CompletableFuture<V>> supplier) { try { Optional<V> cachedValue = cache.getIfPresent(key); if (cachedValue == null) { return MoreAsyncUtil.getWithDeadline(deadlineTimeMillis, supplier).thenApply(value -> { final Optional<V> existingValue = cache.asMap().putIfAbsent(key, Optional.ofNullable(value)); return existingValue == null ? value : existingValue.orElse(null); }); } else { return CompletableFuture.completedFuture(cachedValue.orElse(null)); } } catch (Exception e) { throw new RecordCoreException("failed getting value", e).addLogInfo("cacheKey", key); } } AsyncLoadingCache(long refreshTimeMillis);  AsyncLoadingCache(long refreshTimeMillis, long deadlineTimeMillis);  AsyncLoadingCache(long refreshTimeMillis, long deadlineTimeMillis, long maxSize); }
AsyncLoadingCache { @SuppressWarnings("squid:S2789") @Nonnull public CompletableFuture<V> orElseGet(@Nonnull K key, @Nonnull Supplier<CompletableFuture<V>> supplier) { try { Optional<V> cachedValue = cache.getIfPresent(key); if (cachedValue == null) { return MoreAsyncUtil.getWithDeadline(deadlineTimeMillis, supplier).thenApply(value -> { final Optional<V> existingValue = cache.asMap().putIfAbsent(key, Optional.ofNullable(value)); return existingValue == null ? value : existingValue.orElse(null); }); } else { return CompletableFuture.completedFuture(cachedValue.orElse(null)); } } catch (Exception e) { throw new RecordCoreException("failed getting value", e).addLogInfo("cacheKey", key); } } AsyncLoadingCache(long refreshTimeMillis);  AsyncLoadingCache(long refreshTimeMillis, long deadlineTimeMillis);  AsyncLoadingCache(long refreshTimeMillis, long deadlineTimeMillis, long maxSize); @SuppressWarnings("squid:S2789") // comparison of null and optional used to differentiate absence of key and presence of null @Nonnull CompletableFuture<V> orElseGet(@Nonnull K key, @Nonnull Supplier<CompletableFuture<V>> supplier); long getRefreshTimeSeconds(); long getMaxSize(); void clear(); @Override String toString(); }
AsyncLoadingCache { @SuppressWarnings("squid:S2789") @Nonnull public CompletableFuture<V> orElseGet(@Nonnull K key, @Nonnull Supplier<CompletableFuture<V>> supplier) { try { Optional<V> cachedValue = cache.getIfPresent(key); if (cachedValue == null) { return MoreAsyncUtil.getWithDeadline(deadlineTimeMillis, supplier).thenApply(value -> { final Optional<V> existingValue = cache.asMap().putIfAbsent(key, Optional.ofNullable(value)); return existingValue == null ? value : existingValue.orElse(null); }); } else { return CompletableFuture.completedFuture(cachedValue.orElse(null)); } } catch (Exception e) { throw new RecordCoreException("failed getting value", e).addLogInfo("cacheKey", key); } } AsyncLoadingCache(long refreshTimeMillis);  AsyncLoadingCache(long refreshTimeMillis, long deadlineTimeMillis);  AsyncLoadingCache(long refreshTimeMillis, long deadlineTimeMillis, long maxSize); @SuppressWarnings("squid:S2789") // comparison of null and optional used to differentiate absence of key and presence of null @Nonnull CompletableFuture<V> orElseGet(@Nonnull K key, @Nonnull Supplier<CompletableFuture<V>> supplier); long getRefreshTimeSeconds(); long getMaxSize(); void clear(); @Override String toString(); static final long DEFAULT_DEADLINE_TIME_MILLIS; static final long UNLIMITED; }