DistributedRateLimitedCache implements RateLimitedCache<K> { public boolean acquire(K key, final Runnable cacheHit) { try (Scope ss = tracer.spanBuilder("DistributedRateLimitedCache").startScopedSpan()) { Span span = tracer.getCurrentSpan(); if (cache.get(key) != null) { span.addAnnotation("Found key in cache"); cacheHit.run(); return false; } final String cacheKey = buildKey(key); try { if (memcachedClient.get( cacheKey).toCompletableFuture().get(100, TimeUnit.MILLISECONDS) != null) { memcachedReporter.reportMemcachedHit(); span.addAnnotation("Found key in memcached"); cache.putIfAbsent(key, true); cacheHit.run(); return false; } else { memcachedReporter.reportMemcachedMiss(); } } catch (TimeoutException e) { span.setStatus(Status.INTERNAL.withDescription(e.getMessage())); memcachedReporter.reportMemcachedTimeout(); log.debug("Failed to get key from memecached"); } catch (InterruptedException | ExecutionException e) { span.setStatus(Status.INTERNAL.withDescription(e.getMessage())); memcachedReporter.reportMemcachedError(); log.error("Failed to get key from memecached", e); } span.addAnnotation("Acquiring rate limiter"); rateLimiter.acquire(); span.addAnnotation("Acquired rate limiter"); if (cache.putIfAbsent(key, true) != null) { cacheHit.run(); return false; } else { span.addAnnotation("Add key in memcached " + cacheKey); memcachedClient.set(cacheKey, "true", memcachedTtlSeconds); } return true; } } @java.beans.ConstructorProperties({ "cache", "rateLimiter", "memcachedClient", "memcachedTtlSeconds", "memcachedReporter" })  DistributedRateLimitedCache(final ConcurrentMap<K, Boolean> cache,
        final RateLimiter rateLimiter,
        final MemcacheClient memcachedClient,
        final int memcachedTtlSeconds,
        final MemcachedReporter memcachedReporter); boolean acquire(K key, final Runnable cacheHit); int size();  }
@Test public void localCacheHit(){ cache.putIfAbsent("key1", true); assertFalse(writeCache.acquire("key1", cacheHit)); verify(cacheHit, atLeastOnce()).run(); verify(rateLimiter, never()).acquire(); }
@Test public void memcachedCacheHit() throws ExecutionException, InterruptedException, TimeoutException { doReturn(setupMockedMemcachedGet(key1)).when(memcacheClient).get(Matchers.anyString()); assertFalse(writeCache.acquire(key1, cacheHit)); verify(cacheHit, atLeastOnce()).run(); verify(rateLimiter, never()).acquire(); }