diff options
6 files changed, 40 insertions, 12 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ConfigServerBootstrap.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ConfigServerBootstrap.java index 58c61134bc4..6ab98f5af1c 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/ConfigServerBootstrap.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ConfigServerBootstrap.java @@ -4,6 +4,7 @@ package com.yahoo.vespa.config.server; import com.google.inject.Inject; import com.yahoo.component.AbstractComponent; import com.yahoo.config.provision.Deployer; +import com.yahoo.container.jdisc.state.StateMonitor; import com.yahoo.log.LogLevel; import com.yahoo.vespa.config.server.rpc.RpcServer; import com.yahoo.vespa.config.server.version.VersionState; @@ -23,17 +24,19 @@ public class ConfigServerBootstrap extends AbstractComponent implements Runnable private final Thread serverThread; private final Deployer deployer; private final VersionState versionState; + private final StateMonitor stateMonitor; // The tenants object is injected so that all initial requests handlers are // added to the rpc server before it starts answering rpc requests. - @SuppressWarnings("UnusedParameters") + @SuppressWarnings("WeakerAccess") @Inject public ConfigServerBootstrap(ApplicationRepository applicationRepository, RpcServer server, - Deployer deployer, VersionState versionState) { + Deployer deployer, VersionState versionState, StateMonitor stateMonitor) { this.applicationRepository = applicationRepository; this.server = server; this.deployer = deployer; this.versionState = versionState; + this.stateMonitor = stateMonitor; this.serverThread = new Thread(this, "configserver main"); serverThread.start(); } @@ -62,9 +65,11 @@ public class ConfigServerBootstrap extends AbstractComponent implements Runnable log.log(LogLevel.INFO, "All applications redeployed"); } versionState.saveNewVersion(); + stateMonitor.status(StateMonitor.Status.up); log.log(LogLevel.DEBUG, "Starting RPC server"); server.run(); log.log(LogLevel.DEBUG, "RPC server stopped"); + stateMonitor.status(StateMonitor.Status.down); } } diff --git a/configserver/src/main/resources/configserver-app/services.xml b/configserver/src/main/resources/configserver-app/services.xml index eddba1ee768..fd77fedd789 100644 --- a/configserver/src/main/resources/configserver-app/services.xml +++ b/configserver/src/main/resources/configserver-app/services.xml @@ -6,6 +6,10 @@ <maxthreads>100</maxthreads> <!-- Reduced thread count to minimize memory consumption --> </config> + <config name="container.jdisc.config.health-monitor"> + <initialStatus>initializing</initialStatus> + </config> + <accesslog type="vespa" fileNamePattern="logs/vespa/configserver/access.log.%Y%m%d%H%M%S" rotationScheme="date" symlinkName="access.log" /> <preprocess:include file='access-logging.xml' required='false' /> <component id="com.yahoo.vespa.config.server.ConfigServerBootstrap" bundle="configserver" /> diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ConfigServerBootstrapTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ConfigServerBootstrapTest.java index e0d65055f21..384ae0853d8 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/ConfigServerBootstrapTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ConfigServerBootstrapTest.java @@ -6,7 +6,10 @@ import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ApplicationName; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.TenantName; +import com.yahoo.container.jdisc.config.HealthMonitorConfig; +import com.yahoo.container.jdisc.state.StateMonitor; import com.yahoo.io.IOUtils; +import com.yahoo.jdisc.core.SystemTimer; import com.yahoo.vespa.config.server.deploy.MockDeployer; import com.yahoo.vespa.config.server.host.HostRegistries; import com.yahoo.vespa.config.server.http.SessionHandlerTest; @@ -67,7 +70,9 @@ public class ConfigServerBootstrapTest extends TestWithTenant { assertFalse(myServer.stopped); VersionState versionState = new VersionState(versionFile); assertTrue(versionState.isUpgraded()); - ConfigServerBootstrap bootstrap = new ConfigServerBootstrap(applicationRepository, rpc, (application, timeout) -> Optional.empty(), versionState); + ConfigServerBootstrap bootstrap = + new ConfigServerBootstrap(applicationRepository, rpc, (application, timeout) -> Optional.empty(), versionState, + new StateMonitor(new HealthMonitorConfig(new HealthMonitorConfig.Builder()), new SystemTimer())); waitUntilStarted(rpc, 60000); assertFalse(versionState.isUpgraded()); assertThat(versionState.currentVersion(), is(versionState.storedVersion())); diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/StateHandler.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/StateHandler.java index ce9779b83d9..23c247fa438 100644 --- a/container-core/src/main/java/com/yahoo/container/jdisc/state/StateHandler.java +++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/StateHandler.java @@ -190,7 +190,7 @@ public class StateHandler extends AbstractRequestHandler { private JSONObjectWithLegibleException buildJsonForConsumer(String consumer) throws JSONException { JSONObjectWithLegibleException ret = new JSONObjectWithLegibleException(); ret.put("time", timer.currentTimeMillis()); - ret.put("status", new JSONObjectWithLegibleException().put("code", "up")); + ret.put("status", new JSONObjectWithLegibleException().put("code", getStatus().name())); ret.put(METRICS_PATH, buildJsonForSnapshot(consumer, getSnapshot())); return ret; } @@ -203,6 +203,10 @@ public class StateHandler extends AbstractRequestHandler { } } + private StateMonitor.Status getStatus() { + return monitor.status(); + } + private JSONObjectWithLegibleException buildJsonForSnapshot(String consumer, MetricSnapshot metricSnapshot) throws JSONException { if (metricSnapshot == null) { return new JSONObjectWithLegibleException(); diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/StateMonitor.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/StateMonitor.java index 140257cbcef..6234a96d7a0 100644 --- a/container-core/src/main/java/com/yahoo/container/jdisc/state/StateMonitor.java +++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/StateMonitor.java @@ -6,6 +6,7 @@ import com.yahoo.component.AbstractComponent; import com.yahoo.container.jdisc.config.HealthMonitorConfig; import com.yahoo.jdisc.Timer; import com.yahoo.jdisc.application.MetricConsumer; +import com.yahoo.log.LogLevel; import java.util.Map; import java.util.TreeSet; @@ -14,7 +15,7 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Logger; /** - * A statemonitor keeps track of the current metrics state of a container. + * A state monitor keeps track of the current health and metrics state of a container. * It is used by jDisc to hand out metric update API endpoints to workers through {@link #newMetricConsumer}, * and to inspect the current accumulated state of metrics through {@link #snapshot}. * @@ -23,12 +24,16 @@ import java.util.logging.Logger; public class StateMonitor extends AbstractComponent { private final static Logger log = Logger.getLogger(StateMonitor.class.getName()); + + public enum Status {up, down, initializing}; + private final CopyOnWriteArrayList<StateMetricConsumer> consumers = new CopyOnWriteArrayList<>(); private final Thread thread; private final Timer timer; private final long snapshotIntervalMs; private long lastSnapshotTimeMs; private volatile MetricSnapshot snapshot; + private volatile Status status; private final TreeSet<String> valueNames = new TreeSet<>(); @Inject @@ -36,13 +41,8 @@ public class StateMonitor extends AbstractComponent { this.timer = timer; this.snapshotIntervalMs = (long)(config.snapshot_interval() * TimeUnit.SECONDS.toMillis(1)); this.lastSnapshotTimeMs = timer.currentTimeMillis(); - thread = new Thread(new Runnable() { - - @Override - public void run() { - StateMonitor.this.run(); - } - }, "StateMonitor"); + this.status = Status.valueOf(config.initialStatus()); + thread = new Thread(StateMonitor.this::run, "StateMonitor"); thread.setDaemon(true); thread.start(); } @@ -54,6 +54,13 @@ public class StateMonitor extends AbstractComponent { return consumer; } + public void status(Status status) { + log.log(LogLevel.INFO, "Changing health status code from '" + this.status + "' to '" + status.name() + "'"); + this.status = status; + } + + public Status status() { return status; } + /** Returns the last snapshot taken of the metrics in this system */ public MetricSnapshot snapshot() { return snapshot; diff --git a/container-core/src/main/resources/configdefinitions/health-monitor.def b/container-core/src/main/resources/configdefinitions/health-monitor.def index dc5cdbc6ca4..5e70c72ae3f 100644 --- a/container-core/src/main/resources/configdefinitions/health-monitor.def +++ b/container-core/src/main/resources/configdefinitions/health-monitor.def @@ -4,3 +4,6 @@ namespace=container.jdisc.config # How far between snapshots. 5 minutes by default snapshot_interval double default=300 + +# Initial status used in /state/v1/health API (value for 'code' in 'status'). See StateMonitor for valid values +initialStatus string default="up" |