From 4516a92be42a9f78969a18a11a70a1cd1c996f77 Mon Sep 17 00:00:00 2001 From: bhuism Date: Sat, 11 Jul 2020 21:44:59 +0200 Subject: [PATCH] better caching --- Dockerfile | 1 + pom.xml | 42 ++++++++++------- .../nl/appsource/badge/BadgeApplication.java | 11 ++++- .../badge/controller/ActuatorController.java | 2 + .../controller/ActuatorControllerImpl.java | 6 +++ .../appsource/badge/expected/GitHubImpl.java | 13 +++--- .../appsource/badge/expected/GitLabImpl.java | 18 ++++++-- .../nl/appsource/badge/expected/MyCache.java | 4 +- .../appsource/badge/expected/MyCacheImpl.java | 45 ++++++++++++------- .../java/nl/appsource/badge/lib/Widths.java | 3 +- .../appsource/badge/model/actuator/Info.java | 4 +- .../badge/model/github/GitHubResponse.java | 2 +- 12 files changed, 104 insertions(+), 47 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8dacfb2..9166637 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,4 @@ FROM scratch +EXPOSE 8080 COPY target/badge /badge ENTRYPOINT [ "/badge", "-Djava.io.tmpdir=/", "-Dspring.profiles.active=production", "-XX:+PrintGC", "-XX:+VerboseGC", "--expert-options-all", "-Xmn32m", "-Xmx64m" ] diff --git a/pom.xml b/pom.xml index 4d179da..f47f069 100644 --- a/pom.xml +++ b/pom.xml @@ -87,6 +87,18 @@ badge + + com.github.spotbugs + spotbugs-maven-plugin + 4.0.4 + + + com.github.spotbugs + spotbugs + 4.0.6 + + + org.springframework.boot spring-boot-maven-plugin @@ -108,21 +120,6 @@ - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - - native @@ -197,4 +194,19 @@ + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + diff --git a/src/main/java/nl/appsource/badge/BadgeApplication.java b/src/main/java/nl/appsource/badge/BadgeApplication.java index 602b1c6..a8f4043 100644 --- a/src/main/java/nl/appsource/badge/BadgeApplication.java +++ b/src/main/java/nl/appsource/badge/BadgeApplication.java @@ -7,9 +7,13 @@ import nl.appsource.badge.controller.ActuatorControllerImpl; import nl.appsource.badge.controller.BadgeController; import nl.appsource.badge.controller.BadgeControllerImpl; +import nl.appsource.badge.controller.BadgeStatus; import nl.appsource.badge.expected.FixedImpl; import nl.appsource.badge.expected.GitHubImpl; import nl.appsource.badge.expected.GitLabImpl; +import nl.appsource.badge.expected.MyCache; +import nl.appsource.badge.expected.MyCacheImpl; +import nl.appsource.badge.model.actuator.Info; import nl.appsource.badge.output.ShieldsIo; import nl.appsource.badge.output.Svg; import org.springframework.core.io.DefaultResourceLoader; @@ -40,6 +44,8 @@ public class BadgeApplication { private static final MediaType IMAGE_SVGXML = new MediaType("image", "svg+xml", UTF_8); + public static final MyCache cache = new MyCacheImpl<>(); + private static final Consumer NOCACHE_HEADERS = (header) -> { header.set(HttpHeaders.EXPIRES, "0"); header.setPragma("no-cache"); @@ -84,7 +90,8 @@ private static class RouterCall { new RouterCall("/fixed/actuator/{latest}", APPLICATION_JSON, (r) -> badgeController.shieldsIoActuator(r.pathVariable("owner"), r.pathVariable("repo"), r.pathVariable("branch"), r.param("actuator_url").get())), new RouterCall("/github/actuator/{owner}/{repo}/{branch}", APPLICATION_JSON, (r) -> badgeController.shieldsIoActuator(r.pathVariable("latest"), r.param("actuator_url").get())), new RouterCall("/actuator/info", APPLICATION_JSON, (r) -> actuatorController.info()), - new RouterCall("/actuator/health", APPLICATION_JSON, (r) -> actuatorController.health()) + new RouterCall("/actuator/health", APPLICATION_JSON, (r) -> actuatorController.health()), + new RouterCall("/actuator/cache", APPLICATION_JSON, (r) -> actuatorController.cache()) ).forEach(rc -> { router.GET(rc.pattern, (r) -> NOCACHES.get().contentType(rc.contentType).body(rc.handlerFunction.apply(r))); router.HEAD(rc.pattern, (r) -> NOCACHES.get().contentType(rc.contentType).build()); @@ -103,6 +110,8 @@ private static class RouterCall { public static void main(String[] args) throws IOException { + System.out.println("result: " + Info.Git.Commit.class.toString()); + final ClassLoader defaultClassLoader = ClassUtils.getDefaultClassLoader(); final Resource resource = new DefaultResourceLoader(defaultClassLoader).getResource("banner.txt"); final String banner = StreamUtils.copyToString(resource.getInputStream(), UTF_8); diff --git a/src/main/java/nl/appsource/badge/controller/ActuatorController.java b/src/main/java/nl/appsource/badge/controller/ActuatorController.java index 36f3dc4..c824497 100644 --- a/src/main/java/nl/appsource/badge/controller/ActuatorController.java +++ b/src/main/java/nl/appsource/badge/controller/ActuatorController.java @@ -6,4 +6,6 @@ public interface ActuatorController { String health(); + String cache(); + } diff --git a/src/main/java/nl/appsource/badge/controller/ActuatorControllerImpl.java b/src/main/java/nl/appsource/badge/controller/ActuatorControllerImpl.java index 369caec..1442b7b 100644 --- a/src/main/java/nl/appsource/badge/controller/ActuatorControllerImpl.java +++ b/src/main/java/nl/appsource/badge/controller/ActuatorControllerImpl.java @@ -1,5 +1,6 @@ package nl.appsource.badge.controller; +import nl.appsource.badge.BadgeApplication; import org.springframework.core.io.ClassPathResource; import org.springframework.util.FileCopyUtils; @@ -26,4 +27,9 @@ public String health() { return "{\"status\": \"UP\"}"; } + @Override + public String cache() { + return "{\"size\": " + BadgeApplication.cache.size() + "}"; + } + } diff --git a/src/main/java/nl/appsource/badge/expected/GitHubImpl.java b/src/main/java/nl/appsource/badge/expected/GitHubImpl.java index b040c37..a142e60 100644 --- a/src/main/java/nl/appsource/badge/expected/GitHubImpl.java +++ b/src/main/java/nl/appsource/badge/expected/GitHubImpl.java @@ -1,6 +1,5 @@ package nl.appsource.badge.expected; -import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import nl.appsource.badge.controller.BadgeException; @@ -31,6 +30,7 @@ import static java.lang.Math.min; import static java.util.stream.Collectors.joining; +import static nl.appsource.badge.BadgeApplication.cache; import static nl.appsource.badge.controller.BadgeStatus.Status.ERROR; import static nl.appsource.badge.controller.BadgeStatus.Status.LATEST; import static nl.appsource.badge.controller.BadgeStatus.Status.OUTDATED; @@ -55,9 +55,6 @@ public class GitHubImpl implements GitHub { private final Environment environment; - @Getter - private final MyCache cache = new MyCacheImpl<>(); - private final BiFunction safeHeaderPrint = (responseHeaders, key) -> responseHeaders == null ? null : key + "=" + Optional.ofNullable(responseHeaders.get(key)) @@ -71,7 +68,7 @@ public class GitHubImpl implements GitHub { public BadgeStatus getBadgeStatus(final String owner, final String repo, final String branch, final String commit_sha) throws BadgeException { - final BadgeStatus cacheValue = getCache().getIfPresent(owner + "/" + repo + "/" + commit_sha); + final BadgeStatus cacheValue = cache.getIfPresent(getKey(owner, repo, branch, commit_sha)); if (cacheValue != null) { return cacheValue; @@ -127,7 +124,7 @@ private BadgeStatus callGitHub(final String owner, final String repo, final Stri badgeStatus = new BadgeStatus(OUTDATED, commit_sha_short); } - getCache().put(owner + "/" + repo + "/" + commit_sha, badgeStatus); + cache.put(getKey(owner, repo, branch, commit_sha), badgeStatus); return badgeStatus; } else { @@ -149,6 +146,10 @@ private BadgeStatus callGitHub(final String owner, final String repo, final Stri } + private String getKey(final String owner, final String repo, final String branch, final String commit_sha) { + return owner + "/" + repo + "/" + branch + "/" + commit_sha; + } + private String getToken() { final String token = System.getenv("GITHUB_TOKEN"); diff --git a/src/main/java/nl/appsource/badge/expected/GitLabImpl.java b/src/main/java/nl/appsource/badge/expected/GitLabImpl.java index fc0f539..ea899e3 100644 --- a/src/main/java/nl/appsource/badge/expected/GitLabImpl.java +++ b/src/main/java/nl/appsource/badge/expected/GitLabImpl.java @@ -20,6 +20,7 @@ import static java.lang.Math.abs; import static java.lang.Math.min; import static java.util.Arrays.asList; +import static nl.appsource.badge.BadgeApplication.cache; import static nl.appsource.badge.controller.BadgeStatus.Status.ERROR; import static nl.appsource.badge.controller.BadgeStatus.Status.LATEST; import static nl.appsource.badge.controller.BadgeStatus.Status.OUTDATED; @@ -36,7 +37,16 @@ public class GitLabImpl implements GitLab { @Override public BadgeStatus getBadgeStatus(final String id, final String branch, final String commit_sha) throws BadgeException { - return callGitLab(id, branch, commit_sha); + + final BadgeStatus cacheValue = cache.getIfPresent(getKey(id, branch, commit_sha)); + + if (cacheValue != null) { + return cacheValue; + } else { + return callGitLab(id, branch, commit_sha); + } + + } private BadgeStatus callGitLab(final String id, final String branch, final String commit_sha) throws BadgeException { @@ -47,11 +57,9 @@ private BadgeStatus callGitLab(final String id, final String branch, final Strin final HttpHeaders requestHeaders = new HttpHeaders(); - final String token = getToken(); if (StringUtils.hasText(token)) { - log.info("Using token: " + token); requestHeaders.add(AUTHORIZATION, "bearer " + token); } @@ -81,6 +89,7 @@ private BadgeStatus callGitLab(final String id, final String branch, final Strin badgeStatus = new BadgeStatus(OUTDATED, commit_sha_short); } + cache.put(getKey(id, branch, commit_sha), badgeStatus); return badgeStatus; } else { @@ -111,6 +120,9 @@ private String getUrl() { } + private String getKey(String id, String branch, String commit_sha) { + return id + "/" + branch + "/" + commit_sha; + } private String getToken() { diff --git a/src/main/java/nl/appsource/badge/expected/MyCache.java b/src/main/java/nl/appsource/badge/expected/MyCache.java index 17e9314..312c29b 100644 --- a/src/main/java/nl/appsource/badge/expected/MyCache.java +++ b/src/main/java/nl/appsource/badge/expected/MyCache.java @@ -1,9 +1,11 @@ package nl.appsource.badge.expected; -interface MyCache { +public interface MyCache { V getIfPresent(K key); void put(K key, V value); + int size(); + } diff --git a/src/main/java/nl/appsource/badge/expected/MyCacheImpl.java b/src/main/java/nl/appsource/badge/expected/MyCacheImpl.java index 2fab95d..ce26628 100644 --- a/src/main/java/nl/appsource/badge/expected/MyCacheImpl.java +++ b/src/main/java/nl/appsource/badge/expected/MyCacheImpl.java @@ -2,36 +2,49 @@ import lombok.extern.slf4j.Slf4j; +import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; @Slf4j public class MyCacheImpl implements MyCache { - private final ConcurrentHashMap _cache = new ConcurrentHashMap<>(); - - public MyCacheImpl() { + private final static long EXPIRED_IN_SECONDS = 15; - new Thread(() -> { - try { - while (true) { - Thread.sleep(60 * 1000); - _cache.clear(); - } - } catch (final InterruptedException e) { - log.error("", e); - } - }).start(); - - } + private final ConcurrentHashMap _cache = new ConcurrentHashMap<>(); + private final ConcurrentHashMap _timestamp = new ConcurrentHashMap<>(); @Override public V getIfPresent(final K key) { + synchronized (this) { + + final Long expired = System.currentTimeMillis() + (EXPIRED_IN_SECONDS * 1000); + + _timestamp.keySet().removeAll( + _timestamp + .entrySet() + .stream() + .filter(e -> e.getValue() < expired) + .map(Entry::getKey) + .map(_cache::remove) + .collect(Collectors.toSet())) + ; + } return _cache.get(key); } @Override public void put(final K key, final V value) { - _cache.put(key, value); + synchronized (this) { + _cache.put(key, value); + _timestamp.put(key, System.currentTimeMillis()); + } } + @Override + public int size() { + synchronized (this) { + return _cache.size(); + } + } } diff --git a/src/main/java/nl/appsource/badge/lib/Widths.java b/src/main/java/nl/appsource/badge/lib/Widths.java index 872a875..ae888d4 100644 --- a/src/main/java/nl/appsource/badge/lib/Widths.java +++ b/src/main/java/nl/appsource/badge/lib/Widths.java @@ -1,7 +1,6 @@ package nl.appsource.badge.lib; import java.util.ArrayList; -import java.util.Objects; import static java.util.Arrays.asList; @@ -15,7 +14,7 @@ public static int getWidthOfString(final String text) { ; } - public static final ArrayList simpleWidths = new ArrayList<>(asList( + private static final ArrayList simpleWidths = new ArrayList<>(asList( null , null , null diff --git a/src/main/java/nl/appsource/badge/model/actuator/Info.java b/src/main/java/nl/appsource/badge/model/actuator/Info.java index f7eb5bc..d72dbdb 100644 --- a/src/main/java/nl/appsource/badge/model/actuator/Info.java +++ b/src/main/java/nl/appsource/badge/model/actuator/Info.java @@ -15,7 +15,7 @@ public class Info { @Getter @Setter @JsonIgnoreProperties(ignoreUnknown = true) - public class Git { + public static class Git { private String branch; @@ -23,7 +23,7 @@ public class Git { @Getter @Setter @JsonIgnoreProperties(ignoreUnknown = true) - public class Commit { + public static class Commit { private String id; private String time; diff --git a/src/main/java/nl/appsource/badge/model/github/GitHubResponse.java b/src/main/java/nl/appsource/badge/model/github/GitHubResponse.java index b356a55..a80ca5c 100644 --- a/src/main/java/nl/appsource/badge/model/github/GitHubResponse.java +++ b/src/main/java/nl/appsource/badge/model/github/GitHubResponse.java @@ -18,7 +18,7 @@ public class GitHubResponse { @Getter @Setter @JsonIgnoreProperties(ignoreUnknown = true) - public class Commit { + public static class Commit { private String sha; private String url;