Skip to content

Commit

Permalink
Get cluster health from v1/info
Browse files Browse the repository at this point in the history
  • Loading branch information
willmostly committed Mar 1, 2024
1 parent e2aaa0e commit 6b66c61
Show file tree
Hide file tree
Showing 11 changed files with 278 additions and 28 deletions.
6 changes: 1 addition & 5 deletions docs/quickstart-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@ dataStore:
driver: org.postgresql.Driver

clusterStatsConfiguration:
useApi: true

backendState:
username: gateway
ssl: false
monitorType: INFO_API

modules:
- io.trino.gateway.ha.module.HaGatewayProviderModule
Expand Down
6 changes: 1 addition & 5 deletions gateway-ha/gateway-ha-config-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,8 @@ dataStore:
driver: org.postgresql.Driver
queryHistoryHoursRetention: 24

backendState:
username: lb_query
ssl: false

clusterStatsConfiguration:
useApi: true
monitorType: INFO_API

server:
applicationConnectors:
Expand Down
6 changes: 1 addition & 5 deletions gateway-ha/gateway-ha-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,8 @@ dataStore:
driver: org.postgresql.Driver
queryHistoryHoursRetention: 24

backendState:
username: lb_query
ssl: false

clusterStatsConfiguration:
useApi: true
monitorType: INFO_API

server:
applicationConnectors:
Expand Down
32 changes: 31 additions & 1 deletion gateway-ha/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,16 @@
</exclusions>
</dependency>

<dependency>
<groupId>io.airlift</groupId>
<artifactId>http-client</artifactId>
</dependency>

<dependency>
<groupId>io.airlift</groupId>
<artifactId>json</artifactId>
</dependency>

<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-assets</artifactId>
Expand Down Expand Up @@ -239,6 +249,13 @@
<artifactId>jakarta.ws.rs-api</artifactId>
</dependency>

<!-- Prevent a ClassNotFoundException caused by io.dropwizard.jackson.Jackson:newObjectMapper
calling findModules() indiscriminately-->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
Expand Down Expand Up @@ -506,9 +523,22 @@
</executions>
</plugin>

<!-- maven shade plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<configuration>
<ignoredDependencies>
<ignoredDependency>joda-time:joda-time</ignoredDependency>
</ignoredDependencies>
</configuration>
</execution>
</executions>
</plugin>

<!-- maven shade plugin -->
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
Expand Down
67 changes: 67 additions & 0 deletions gateway-ha/src/main/java/io/trino/client/NodeVersion.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.trino.client;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Objects;

import static java.util.Objects.requireNonNull;

// copy of https://github.com/trinodb/trino/blob/f83854687229df1ae3325249e7bcd29f03d0943c/client/trino-client/src/main/java/io/trino/client/NodeVersion.java
public class NodeVersion
{
public static final NodeVersion UNKNOWN = new NodeVersion("<unknown>");

private final String version;

@JsonCreator
public NodeVersion(@JsonProperty("version") String version)
{
this.version = requireNonNull(version, "version is null");
}

@JsonProperty
public String getVersion()
{
return version;
}

@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

NodeVersion that = (NodeVersion) o;
return Objects.equals(version, that.version);
}

@Override
public int hashCode()
{
return Objects.hash(version);
}

@Override
public String toString()
{
return version;
}
}
73 changes: 73 additions & 0 deletions gateway-ha/src/main/java/io/trino/client/ServerInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.trino.client;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Objects;

import static com.google.common.base.MoreObjects.toStringHelper;
import static java.lang.Boolean.parseBoolean;
import static java.util.Objects.requireNonNull;

// based on https://github.com/trinodb/trino/blob/f83854687229df1ae3325249e7bcd29f03d0943c/client/trino-client/src/main/java/io/trino/client/ServerInfo.java#L28
public class ServerInfo
{
private final boolean starting;

@JsonCreator
public ServerInfo(
// Defining as a String allows using requireNonNull to ensure starting is present
@JsonProperty("starting") String starting)
{
this.starting = parseBoolean(requireNonNull(starting, "starting is null"));
}

@JsonProperty
public boolean isStarting()
{
return starting;
}

@JsonProperty

@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

ServerInfo that = (ServerInfo) o;
return Objects.equals(starting, that.starting);
}

@Override
public int hashCode()
{
return starting ? 1 : 0;
}

@Override
public String toString()
{
return toStringHelper(this)
.add("starting", starting)
.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.trino.gateway.ha.clustermonitor;

import io.airlift.http.client.HttpClient;
import io.airlift.http.client.HttpClientConfig;
import io.airlift.http.client.Request;
import io.airlift.http.client.jetty.JettyHttpClient;
import io.trino.client.ServerInfo;
import io.trino.gateway.ha.config.ProxyBackendConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;

import static io.airlift.http.client.HttpUriBuilder.uriBuilderFrom;
import static io.airlift.http.client.JsonResponseHandler.createJsonResponseHandler;
import static io.airlift.http.client.Request.Builder.prepareGet;
import static io.airlift.json.JsonCodec.jsonCodec;

public class ClusterStatsInfoApiMonitor
implements ClusterStatsMonitor
{
//TODO: make client options configurable
private static final HttpClient client = new JettyHttpClient(new HttpClientConfig());
private static final Logger log = LoggerFactory.getLogger(ClusterStatsInfoApiMonitor.class);

@Override
public ClusterStats monitor(ProxyBackendConfiguration backend)
{
return ClusterStats.builder(backend.getName()).healthy(isReadyStatus(backend.getProxyTo()))
.proxyTo(backend.getProxyTo())
.externalUrl(backend.getExternalUrl())
.routingGroup(backend.getRoutingGroup()).build();
}

private boolean isReadyStatus(String baseUrl)
{
Request request = prepareGet()
.setUri(uriBuilderFrom(URI.create(baseUrl)).appendPath("/v1/info").build())
.build();

try {
ServerInfo serverInfo = client.execute(request, createJsonResponseHandler(jsonCodec(ServerInfo.class)));
return !serverInfo.isStarting();
}
catch (Exception e) {
log.error("Exception checking {} for health: {} ", request.getUri(), e.getMessage());
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@

public class ClusterStatsConfiguration
{
private boolean useApi;
private ClusterStatsMonitorType monitorType;

public ClusterStatsConfiguration() {}

public boolean isUseApi()
public ClusterStatsMonitorType getMonitorType()
{
return this.useApi;
return monitorType;
}

public void setUseApi(boolean useApi)
public void setMonitorType(ClusterStatsMonitorType monitorType)
{
this.useApi = useApi;
this.monitorType = monitorType;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.trino.gateway.ha.config;

public enum ClusterStatsMonitorType
{
NOOP,
INFO_API,
UI_API,
JDBC
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import io.dropwizard.core.setup.Environment;
import io.trino.gateway.baseapp.AppModule;
import io.trino.gateway.ha.clustermonitor.ClusterStatsHttpMonitor;
import io.trino.gateway.ha.clustermonitor.ClusterStatsInfoApiMonitor;
import io.trino.gateway.ha.clustermonitor.ClusterStatsJdbcMonitor;
import io.trino.gateway.ha.clustermonitor.ClusterStatsMonitor;
import io.trino.gateway.ha.clustermonitor.NoopClusterStatsMonitor;
Expand All @@ -41,13 +42,13 @@ public ClusterStatsMonitor getClusterStatsMonitor()
{
ClusterStatsConfiguration clusterStatsConfig = config.getClusterStatsConfiguration();
if (config.getBackendState() == null) {
return new NoopClusterStatsMonitor();
}
if (clusterStatsConfig.isUseApi()) {
return new ClusterStatsHttpMonitor(config.getBackendState());
}
else {
return new ClusterStatsJdbcMonitor(config.getBackendState());
return new ClusterStatsInfoApiMonitor();
}
return switch (clusterStatsConfig.getMonitorType()) {
case INFO_API -> new ClusterStatsInfoApiMonitor();
case UI_API -> new ClusterStatsHttpMonitor(config.getBackendState());
case JDBC -> new ClusterStatsJdbcMonitor(config.getBackendState());
case NOOP -> new NoopClusterStatsMonitor();
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ public void testJdbcMonitor()
testClusterStatsMonitor(ClusterStatsJdbcMonitor::new);
}

@Test
public void testInfoApiMonitor()
{
testClusterStatsMonitor(ignored -> new ClusterStatsInfoApiMonitor());
}

private void testClusterStatsMonitor(Function<BackendStateConfiguration, ClusterStatsMonitor> monitorFactory)
{
BackendStateConfiguration backendStateConfiguration = new BackendStateConfiguration();
Expand Down

0 comments on commit 6b66c61

Please sign in to comment.