Healthcheck (#715)

* Add a pid-path parameter to write a pid file that can be used as a healthcheck

Signed-off-by: Antoine Toulme <antoine@lunar-ocean.com>

* Add healthcheck to the Dockerfile

Signed-off-by: Antoine Toulme <antoine@lunar-ocean.com>

* fix assertj use

Signed-off-by: Antoine Toulme <antoine@lunar-ocean.com>

* Fix unit tests

Signed-off-by: Antoine Toulme <antoine@lunar-ocean.com>
pull/751/head
Antoine Toulme 5 years ago committed by GitHub
parent 74940d507e
commit 1d493597f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      besu/src/main/java/org/hyperledger/besu/Runner.java
  2. 7
      besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java
  3. 13
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  4. 3
      besu/src/test/java/org/hyperledger/besu/RunnerTest.java
  5. 1
      besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java
  6. 1
      besu/src/test/resources/everything_config.toml
  7. 2
      docker/Dockerfile

@ -29,7 +29,11 @@ import org.hyperledger.besu.nat.NatService;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
@ -53,6 +57,7 @@ public class Runner implements AutoCloseable {
private final NetworkRunner networkRunner;
private final NatService natService;
private final Optional<Path> pidPath;
private final Optional<JsonRpcHttpService> jsonRpc;
private final Optional<GraphQLHttpService> graphQLHttp;
private final Optional<WebSocketService> websocketRpc;
@ -75,12 +80,14 @@ public class Runner implements AutoCloseable {
final Optional<MetricsService> metrics,
final BesuController<?> besuController,
final Path dataDir,
final Optional<Path> pidPath,
final Optional<TransactionLogBloomCacher> transactionLogBloomCacher,
final Blockchain blockchain) {
this.vertx = vertx;
this.networkRunner = networkRunner;
this.natService = natService;
this.graphQLHttp = graphQLHttp;
this.pidPath = pidPath;
this.jsonRpc = jsonRpc;
this.websocketRpc = websocketRpc;
this.metrics = metrics;
@ -114,6 +121,7 @@ public class Runner implements AutoCloseable {
writeBesuPortsToFile();
writeBesuNetworksToFile();
autoTransactionLogBloomCachingService.ifPresent(AutoTransactionLogBloomCachingService::start);
writePidFile();
} catch (final Exception ex) {
LOG.error("Startup failed", ex);
throw new IllegalStateException(ex);
@ -256,6 +264,28 @@ public class Runner implements AutoCloseable {
"This file contains the IP Addresses (global and local) used by the running instance of Besu");
}
private void writePidFile() {
pidPath.ifPresent(
path -> {
String pid = "";
try {
pid = Long.toString(ProcessHandle.current().pid());
} catch (Throwable t) {
}
try {
Files.write(
path,
pid.getBytes(StandardCharsets.UTF_8),
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.WRITE);
path.toFile().deleteOnExit();
} catch (IOException e) {
LOG.error("Error writing PID file", e);
}
});
}
public Optional<Integer> getJsonRpcPort() {
return jsonRpc.map(service -> service.socketAddress().getPort());
}

@ -143,6 +143,7 @@ public class RunnerBuilder {
private GraphQLConfiguration graphQLConfiguration;
private WebSocketConfiguration webSocketConfiguration;
private Path dataDir;
private Optional<Path> pidPath = Optional.empty();
private MetricsConfiguration metricsConfiguration;
private ObservableMetricsSystem metricsSystem;
private Optional<PermissioningConfiguration> permissioningConfiguration = Optional.empty();
@ -241,6 +242,11 @@ public class RunnerBuilder {
return this;
}
public RunnerBuilder pidPath(final Path pidPath) {
this.pidPath = Optional.ofNullable(pidPath);
return this;
}
public RunnerBuilder dataDir(final Path dataDir) {
this.dataDir = dataDir;
return this;
@ -546,6 +552,7 @@ public class RunnerBuilder {
metricsService,
besuController,
dataDir,
pidPath,
autoLogBloomCaching ? blockchainQueries.getTransactionLogBloomCacher() : Optional.empty(),
context.getBlockchain());
}

@ -848,6 +848,12 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private final Integer pruningBlockConfirmations =
PrunerConfiguration.DEFAULT_PRUNING_BLOCK_CONFIRMATIONS;
@CommandLine.Option(
names = {"--pid-path"},
paramLabel = MANDATORY_PATH_FORMAT_HELP,
description = "Path to PID file (optional)")
private final Path pidPath = null;
private EthNetworkConfig ethNetworkConfig;
private JsonRpcConfiguration jsonRpcConfiguration;
private GraphQLConfiguration graphQLConfiguration;
@ -1068,7 +1074,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
webSocketConfiguration,
metricsConfiguration,
permissioningConfiguration,
staticNodes);
staticNodes,
pidPath);
}
private BesuCommand startPlugins() {
@ -1727,7 +1734,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
final WebSocketConfiguration webSocketConfiguration,
final MetricsConfiguration metricsConfiguration,
final Optional<PermissioningConfiguration> permissioningConfiguration,
final Collection<EnodeURL> staticNodes) {
final Collection<EnodeURL> staticNodes,
final Path pidPath) {
checkNotNull(runnerBuilder);
@ -1753,6 +1761,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.graphQLConfiguration(graphQLConfiguration)
.jsonRpcConfiguration(jsonRpcConfiguration)
.webSocketConfiguration(webSocketConfiguration)
.pidPath(pidPath)
.dataDir(dataDir())
.bannedNodeIds(bannedNodeIds)
.metricsSystem(metricsSystem)

@ -193,6 +193,7 @@ public final class RunnerTest {
final GraphQLConfiguration aheadGraphQLConfiguration = graphQLConfiguration();
final WebSocketConfiguration aheadWebSocketConfiguration = wsRpcConfiguration();
final MetricsConfiguration aheadMetricsConfiguration = metricsConfiguration();
final Path pidPath = temp.getRoot().toPath().resolve("pid");
final RunnerBuilder runnerBuilder =
new RunnerBuilder()
.vertx(vertx)
@ -213,11 +214,13 @@ public final class RunnerTest {
.webSocketConfiguration(aheadWebSocketConfiguration)
.metricsConfiguration(aheadMetricsConfiguration)
.dataDir(dbAhead)
.pidPath(pidPath)
.besuPluginContext(new BesuPluginContextImpl())
.build();
try {
runnerAhead.start();
assertThat(pidPath.toFile().exists()).isTrue();
final SynchronizerConfiguration syncConfigBehind =
SynchronizerConfiguration.builder()

@ -223,6 +223,7 @@ public abstract class CommandTestAbstract {
when(mockRunnerBuilder.identityString(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.besuPluginContext(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.autoLogBloomCaching(anyBoolean())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.pidPath(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.build()).thenReturn(mockRunner);
lenient()

@ -12,6 +12,7 @@
data-path="~/besudata"
logging="INFO"
node-private-key-file="./path/to/privateKey"
pid-path="~/.pid"
# P2P network
identity="PegaSysEng"

@ -15,9 +15,11 @@ EXPOSE 8545 8546 8547 30303
ENV BESU_RPC_HTTP_HOST 0.0.0.0
ENV BESU_RPC_WS_HOST 0.0.0.0
ENV BESU_GRAPHQL_HTTP_HOST 0.0.0.0
ENV BESU_PID_PATH "/tmp/pid"
ENV PATH="/opt/besu/bin:${PATH}"
ENTRYPOINT ["besu"]
HEALTHCHECK --start-period=5s --interval=5s --timeout=1s --retries=10 CMD bash -c "[ -f /tmp/pid ]"
# Build-time metadata as defined at http://label-schema.org
ARG BUILD_DATE

Loading…
Cancel
Save