Skip to content

Commit

Permalink
Cache docker container info for fast response times (500ms -> 1ms) (#18)
Browse files Browse the repository at this point in the history
Simple cache in front of DockerContainerInfo
  • Loading branch information
SerialVelocity authored Oct 31, 2018
1 parent fcf0acf commit 4f305fc
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2017 Palantir Technologies, Inc. All rights reserved.
*/

package com.palantir.docker.proxy;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
* CachingDockerContainerInfo will cache and refresh container info. If the refresh
* fails four times in a row, the entry will be removed and the next call will return
* the exception to you if it happens again.
*/
public class CachingDockerContainerInfo implements DockerContainerInfo {
private final DockerContainerInfo delegate;
private final LoadingCache<String, Optional<String>> ipForHostCache;
private final LoadingCache<String, Optional<String>> hostForIpCache;

public CachingDockerContainerInfo(DockerContainerInfo delegate) {
// It takes up to 1s to query docker so we set this to be under a multiple of 5, 10, and 15 by at least 2s
this(delegate, 53, TimeUnit.SECONDS);
}

@VisibleForTesting
CachingDockerContainerInfo(DockerContainerInfo delegate, long refreshDuration, TimeUnit refreshUnit) {
this.delegate = delegate;
this.ipForHostCache = CacheBuilder.newBuilder()
.expireAfterWrite(4 * refreshDuration, refreshUnit)
.refreshAfterWrite(refreshDuration, refreshUnit)
.build(CacheLoader.from(hostname -> delegate.getIpForHost(hostname)));
this.hostForIpCache = CacheBuilder.newBuilder()
.expireAfterWrite(4 * refreshDuration, refreshUnit)
.refreshAfterWrite(refreshDuration / 4, refreshUnit)
.build(CacheLoader.from(hostname -> delegate.getHostForIp(hostname)));
}

@Override
public Optional<String> getIpForHost(String hostname) {
Optional<String> ip = ipForHostCache.getUnchecked(hostname);
if (!ip.isPresent()) {
ipForHostCache.invalidate(hostname);
}
return ip;
}

@Override
public Optional<String> getHostForIp(String ip) {
Optional<String> host = hostForIpCache.getUnchecked(ip);
if (!host.isPresent()) {
hostForIpCache.invalidate(ip);
}
return host;
}

@Override
public String getNetworkName() {
return delegate.getNetworkName();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public static List<String> getContainerIdsInDockerComposeProject(
private static List<String> runDockerProcess(DockerExecutable docker, String... args)
throws IOException, InterruptedException {
Process process = docker.execute(args);
if (!process.waitFor(5, TimeUnit.SECONDS) || process.exitValue() != 0) {
if (!process.waitFor(15, TimeUnit.SECONDS) || process.exitValue() != 0) {
throw new IllegalStateException("Unable to execute docker command: " + ImmutableList.copyOf(args));
}
return getLinesFromInputStream(process.getInputStream());
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/palantir/docker/proxy/DockerProxyRule.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ public class DockerProxyRule extends ExternalResource {
public DockerProxyRule(
Function<DockerExecutable, DockerContainerInfo> dockerContainerInfoCreator,
Class<?> classToLogFor) {
this.dockerContainerInfo = dockerContainerInfoCreator.apply(DockerExecutable.builder()
DockerContainerInfo builtDockerContainerInfo = dockerContainerInfoCreator.apply(DockerExecutable.builder()
.dockerConfiguration(DockerMachine.localMachine().build())
.build());
String logDirectory = DockerProxyRule.class.getSimpleName() + "-" + classToLogFor.getSimpleName();
this.dockerContainerInfo = new CachingDockerContainerInfo(builtDockerContainerInfo);
this.dockerComposeRule = DockerComposeRule.builder()
.file(getDockerComposeFile(this.dockerContainerInfo.getNetworkName()).getPath())
.waitingForService("proxy", Container::areAllPortsOpen)
Expand Down
2 changes: 1 addition & 1 deletion versions.props
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
com.palantir.docker.compose:docker-compose-rule-junit4 = 0.33.0
com.palantir.docker.compose:docker-compose-rule-junit4 = 0.34.0
junit:junit = 4.12
net.amygdalum:xrayinterface = 0.3.0
one.util:streamex = 0.6.3
Expand Down

0 comments on commit 4f305fc

Please sign in to comment.