Skip to content

Commit

Permalink
feat: add cached sitemap getter
Browse files Browse the repository at this point in the history
  • Loading branch information
guqing committed Nov 18, 2022
1 parent f6764a1 commit 0abb098
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 35 deletions.
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,21 @@ jar {
}
}

ext {
guava = "31.1-jre"
}
dependencies {
compileOnly 'io.github.guqing:pluggable-suite:0.0.1-SNAPSHOT'
compileOnly "io.swagger.core.v3:swagger-core-jakarta:2.2.0"
compileOnly 'org.springframework.boot:spring-boot-starter-webflux'
compileOnly "com.google.guava:guava:$guava"

compileOnly files("lib/halo-2.0.0-SNAPSHOT-plain.jar")

compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

testImplementation "com.google.guava:guava:$guava"
testImplementation 'org.apache.commons:commons-lang3:3.12.0'
testImplementation 'org.springframework.boot:spring-boot-starter-webflux'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
Expand Down
40 changes: 40 additions & 0 deletions src/main/java/run/halo/sitemap/CachedSitemapGetter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package run.halo.sitemap;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
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<String, String> cache = CacheBuilder.newBuilder()
.concurrencyLevel(Runtime.getRuntime().availableProcessors())
.initialCapacity(8)
.maximumSize(8)
.expireAfterWrite(Duration.ofSeconds(30))
.build();

private final DefaultSitemapEntryLister lister;

public Mono<String> get() {
String cacheKey = "sitemap";
return Mono.fromCallable(() -> cache.get(cacheKey, () -> lister.list()
.collectList()
.map(entries -> {
String xml = new SitemapBuilder()
.buildSitemapXml(entries);
cache.put(cacheKey, xml);
return xml;
})
.defaultIfEmpty(StringUtils.EMPTY)
.block()
))
.subscribeOn(Schedulers.boundedElastic());
}
}
33 changes: 26 additions & 7 deletions src/main/java/run/halo/sitemap/DefaultSitemapEntryLister.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package run.halo.sitemap;

import java.time.Instant;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import run.halo.app.core.extension.Category;
import run.halo.app.core.extension.Post;
import run.halo.app.core.extension.SinglePage;
Expand All @@ -20,7 +22,6 @@
@Component
@AllArgsConstructor
public class DefaultSitemapEntryLister implements SitemapEntryLister {

private final ReactiveExtensionClient client;
private final SitemapGeneratorOptions options;

Expand All @@ -34,27 +35,45 @@ public Flux<SitemapEntry> list() {
}

private Flux<String> listPostUrls() {
return client.list(Post.class, post -> post.isPublished() && !post.isDeleted(), null)
return client.list(Post.class, post -> post.isPublished() && !post.isDeleted()
&& Post.VisibleEnum.PUBLIC.equals(post.getSpec().getVisible()),
defaultComparator())
.map(post -> post.getStatusOrDefault().getPermalink());
}

Comparator<Post> defaultComparator() {
Function<Post, Instant> createTime = post -> post.getMetadata().getCreationTimestamp();
Function<Post, String> name = post -> post.getMetadata().getName();
return Comparator.comparing(createTime).thenComparing(name);
}

private Flux<String> listSinglePageUrls() {
return client.list(SinglePage.class, singlePage -> singlePage.isPublished()
&& Objects.equals(false, singlePage.getSpec().getDeleted())
&& ExtensionOperator.isNotDeleted().test(singlePage),
null)
&& ExtensionOperator.isNotDeleted().test(singlePage)
&& Post.VisibleEnum.PUBLIC.equals(singlePage.getSpec().getVisible()),
pageDefaultComparator())
.map(post -> post.getStatusOrDefault().getPermalink());
}

Comparator<SinglePage> pageDefaultComparator() {
Function<SinglePage, Instant> createTime =
page -> page.getMetadata().getCreationTimestamp();
Function<SinglePage, String> name = page -> page.getMetadata().getName();
return Comparator.comparing(createTime).thenComparing(name);
}

private Flux<String> listCategoryUrls() {
return client.list(Category.class,
category -> category.getMetadata().getDeletionTimestamp() == null, null)
category -> category.getMetadata().getDeletionTimestamp() == null,
Comparator.comparing(tag -> tag.getMetadata().getCreationTimestamp()))
.map(category -> category.getStatusOrDefault().getPermalink());
}

private Flux<String> listTagUrls() {
return client.list(Tag.class,
tag -> tag.getMetadata().getDeletionTimestamp() == null, null)
tag -> tag.getMetadata().getDeletionTimestamp() == null,
Comparator.comparing(tag -> tag.getMetadata().getCreationTimestamp()))
.map(tag -> tag.getStatusOrDefault().getPermalink());
}

Expand Down
26 changes: 0 additions & 26 deletions src/main/java/run/halo/sitemap/DefaultSitemapXmlSupplier.java

This file was deleted.

4 changes: 2 additions & 2 deletions src/main/java/run/halo/sitemap/SitemapPluginConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ public SitemapGeneratorOptions sitemapGeneratorOptions()

@Bean
RouterFunction<ServerResponse> sitemapRouterFunction(
DefaultSitemapXmlSupplier sitemapXmlSupplier) {
CachedSitemapGetter cachedSitemapGetter) {
return RouterFunctions.route(GET("/sitemap.xml")
.and(accept(MediaType.TEXT_XML)), request -> sitemapXmlSupplier.get()
.and(accept(MediaType.TEXT_XML)), request -> cachedSitemapGetter.get()
.flatMap(sitemap -> ServerResponse.ok()
.contentType(MediaType.TEXT_XML).bodyValue(sitemap))
);
Expand Down
41 changes: 41 additions & 0 deletions src/test/java/run/halo/sitemap/CachedSitemapGetterTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package run.halo.sitemap;

import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.concurrent.CountDownLatch;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import reactor.core.publisher.Flux;

@ExtendWith(MockitoExtension.class)
public class CachedSitemapGetterTest {
@Mock
private DefaultSitemapEntryLister lister;
private CachedSitemapGetter getter;

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

@Test
void get() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(10);

for (int i = 0; i < countDownLatch.getCount(); i++) {
new Thread(() -> {
getter.get().block();
countDownLatch.countDown();
}).start();
}
countDownLatch.await();
verify(lister, times(1)).list();
}
}

0 comments on commit 0abb098

Please sign in to comment.