Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 15 additions & 21 deletions src/main/java/run/halo/sitemap/CachedSitemapGetter.java
Original file line number Diff line number Diff line change
@@ -1,39 +1,33 @@
package run.halo.sitemap;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.github.benmanes.caffeine.cache.AsyncCache;
import com.github.benmanes.caffeine.cache.Caffeine;
import java.time.Duration;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

@Component
@AllArgsConstructor
public class CachedSitemapGetter {

private final Cache<SitemapGeneratorOptions, String> cache = CacheBuilder.newBuilder()
.concurrencyLevel(Runtime.getRuntime().availableProcessors())
.initialCapacity(8)
.maximumSize(8)
private final AsyncCache<String, String> cache = Caffeine.newBuilder()
.expireAfterWrite(Duration.ofSeconds(30))
.build();
.maximumSize(8)
.buildAsync();

private final DefaultSitemapEntryLister lister;

public Mono<String> get(SitemapGeneratorOptions options) {
return Mono.fromCallable(() -> cache.get(options, () -> lister.list(options)
.collectList()
.map(entries -> {
String xml = new SitemapBuilder()
.buildSitemapXml(entries);
cache.put(options, xml);
return xml;
})
.defaultIfEmpty(StringUtils.EMPTY)
.block()
))
.subscribeOn(Schedulers.boundedElastic());
String key = options.getSiteUrl().toString();
return Mono.fromFuture(() ->
cache.get(key, (k, executor) ->
lister.list(options)
.collectList()
.map(entries -> new SitemapBuilder().buildSitemapXml(entries))
.defaultIfEmpty("")
.toFuture()
)
);
}
}
20 changes: 11 additions & 9 deletions src/test/java/run/halo/sitemap/CachedSitemapGetterTest.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package run.halo.sitemap;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
Expand All @@ -22,33 +24,33 @@ public class CachedSitemapGetterTest {
@Mock
private DefaultSitemapEntryLister lister;
private CachedSitemapGetter getter;
private SitemapGeneratorOptions options;

@BeforeEach
void setUp() {
void setUp() throws MalformedURLException {
when(lister.list(any())).thenReturn(
Flux.just(SitemapEntry.builder().loc("http://localhost:8090/about").build()));
getter = new CachedSitemapGetter(lister);
options = SitemapGeneratorOptions.builder()
.siteUrl(new URL("http://localhost:8090"))
.build();
}

@Test
void get() throws InterruptedException, ExecutionException {
var options = mock(SitemapGeneratorOptions.class);

getter.get(options).block();
verify(lister).list(options);
verify(lister).list(any());

var executorService = Executors.newCachedThreadPool();

List<? extends Future<?>> futures = IntStream.range(0, 10)
.mapToObj(i -> executorService.submit(() -> {
getter.get(options).block();
}))
.mapToObj(i -> executorService.submit(() -> getter.get(options).block()))
.toList();

for (Future<?> future : futures) {
future.get();
}

verify(lister).list(options);
verify(lister, times(1)).list(any());
}
}
Loading