Skip to content

Latest commit

 

History

1,085 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Consul Client for Java

build Quality Gate Status Coverage CodeQL javadoc License: Apache 2.0 Maven Central


🥝 We have now transitioned consul-client from rickfast to kiwiproject. It is released to Maven Central. See the releases for more information. 🥝


Introduction

Simple client for the Consul HTTP API. For more information about the Consul HTTP API, go here.

Background

This library was imported from rickfast/consul-client, which is no longer being maintained per a note from the original maintainer.

Since we are still using this library in services which use Dropwizard and Consul, we decided to import the original repository and continue maintaining it for our own use, and anyone else who might want to use it. We make no guarantees whatsoever about how long we will maintain it, and also plan to make our own changes such as changing the base package name to org.kiwiproject to be consistent with our other libraries.

All other kiwiproject projects are MIT-licensed. However, because the original consul-client uses the Apache 2.0 license, we are keeping the Apache 2.0 license (otherwise to switch to MIT we would have to gain consent of all contributors, which we do not want to do).

Another thing to note is that we imported this repository from the original, so that it is a "disconnected fork". We did not want a reference to the original repository since it is no longer maintained and no changes here will ever be pushed back upstream. Thus, while we maintain the history that this is a fork, it is completely disconnected and is now a standalone (normal) repository.

Migrating from rickfast/consul-client

For the initial version 0.5.0, most likely the only thing you need to change in your POM is the group ID and the version number. However, you should instead go directly to 0.6.0, since there was an issue in the initial release in which the compile time dependencies were not included in the POM released to Maven Central. Other than the POM dependencies and a few minor documentation and minor changes in tests, 0.5.0 and 0.6.0 are basically the same.

If you are using PolicyResponse and/or PolicyListResponse, then you will need to change your code, since datacenters changed from Optional<String> to Optional<List<String>>, so code using either of those will no longer compile. This change was not avoidable, since the original type was incorrect.

Starting with version 0.7.0, the base package changes from com.orbitz to org.kiwiproject. The class names are the same, so existing code only needs to change the base package and recompile.

0.8.0 removes all deprecated methods from AgentClient and KeyValueClient. The methods in AgentClient would have always failed anyway, since Consul no longer has the HTTP endpoints they were calling. Last, there is no direct replacement for the method removed from KeyValueClient.

Installation

Use the following to include consul-client as a dependency in your project.

Gradle:

Groovy:

dependencies {
    implementation 'org.kiwiproject:consul-client:[version]'
}

Kotlin:

dependencies {
    implementation("org.kiwiproject:consul-client:[version]")
}

Maven:

<dependencies>
    <dependency>
        <groupId>org.kiwiproject</groupId>
        <artifactId>consul-client</artifactId>
        <version>[version]</version>
    </dependency>
</dependencies>

Shaded JAR

A shaded JAR is also provided using the Maven Shade Plugin to create an "uber-jar" that includes dependencies. To use the shaded JAR, add a classifier, e.g. in Maven:

<dependency>
    <groupId>org.kiwiproject</groupId>
    <artifactId>consul-client</artifactId>
    <version>[version]</version>
    <classifier>shaded</classifier>
</dependency>

Basic Usage

Example 1: Connect to Consul.

Consul client = Consul.builder().build(); // connect on localhost to default port 8500

Example 2: Register and check your service in with Consul.

AgentClient agentClient = client.agentClient();

String serviceId = "1";
Registration service = ImmutableRegistration.builder()
        .id(serviceId)
        .name("myService")
        .port(8080)
        .check(Registration.RegCheck.ttl(3L)) // registers with a TTL of 3 seconds
        .tags(List.of("tag1"))
        .meta(Map.of("version", "1.0"))
        .build();

agentClient.register(service);

// Check in with Consul (serviceId required only).
// Client will prepend "service:" for service level checks.
// Note that you need to continually check in before the TTL expires; otherwise your service's state will be marked as "critical".
agentClient.pass(serviceId);

Example 3: Find available (healthy) services.

HealthClient healthClient = client.healthClient();

// Discover only "passing" nodes
List<ServiceHealth> nodes = healthClient.getHealthyServiceInstances("DataService").getResponse();

Example 4: Store key/values.

KeyValueClient kvClient = client.keyValueClient();

kvClient.putValue("foo","bar");
        String value=kvClient.getValueAsString("foo").orElseThrow(); // bar

Example 5: Subscribe to value change.

You can use the ConsulCache implementations to easily subscribe to Key-Value changes.

final KeyValueClient kvClient = client.keyValueClient();

kvClient.putValue("foo", "bar");

KVCache cache = KVCache.newCache(kvClient, "foo");
cache.addListener(newValues -> {
    // Cache notifies all paths with "foo" the root path
    // If you want to watch only "foo" value, you must filter other paths
    Optional<Value> newValue = newValues.values().stream()
            .filter(value -> value.getKey().equals("foo"))
            .findAny();

    newValue.ifPresent(value -> {
        // Values are encoded in key/value store, decode it if needed
        Optional<String> decodedValue=newValue.get().getValueAsString();
        decodedValue.ifPresent(v->System.out.printf("Value is: %s%n",v)); //prints "bar"
        });
});
cache.start();
// ...
cache.stop();

Example 6: Subscribe to healthy services

You can also use the ConsulCache implementations to easily subscribe to healthy service changes.

HealthClient healthClient = client.healthClient();
String serviceName = "my-service";

ServiceHealthCache svHealth = ServiceHealthCache.newCache(healthClient, serviceName);
svHealth.addListener((Map<ServiceHealthKey, ServiceHealth> newValues) -> {
    // do something with updated server map
});
svHealth.start();
// ...
svHealth.stop();

Example 7: Find Raft peers.

StatusClient statusClient = client.statusClient();
statusClient.getPeers().forEach(System.out::println);

Example 8: Find Raft leader.

StatusClient statusClient = client.statusClient();
System.out.println(statusClient.getLeader()); // 127.0.0.1:8300

Unix Domain Socket Support

Starting in version 1.12.0, the Consul client can be configured to communicate with the local Consul agent via a Unix domain socket instead of TCP. This bypasses the TCP/IP network stack entirely and can improve reliability in environments where loopback networking may be disrupted (e.g., during infrastructure maintenance windows).

To enable it, configure the Consul agent with a socket address:

addresses {
  http = "unix:///var/run/consul/consul.sock"
}

Then configure the client with the socket path instead of a host/port:

Consul client = Consul.builder()
        .withUnixDomainSocket("/var/run/consul/consul.sock")
        .build();

Dependency

Unix domain socket support depends on junixsocket-core, which is an optional dependency and must be added explicitly if you want to use this feature.

If you are using kiwi-bom for dependency management, the version is managed for you:

<dependency>
    <groupId>com.kohlschutter.junixsocket</groupId>
    <artifactId>junixsocket-core</artifactId>
    <type>pom</type>
</dependency>

Otherwise, specify the version explicitly (see Maven Central for the latest version):

<dependency>
    <groupId>com.kohlschutter.junixsocket</groupId>
    <artifactId>junixsocket-core</artifactId>
    <version>[latest-version]</version>
    <type>pom</type>
</dependency>

JVM Requirements

On Java 24+, you must explicitly enable native access for junixsocket at JVM startup. The correct flag depends on whether your application is modularized:

Non-modularized applications (fat JARs, most Dropwizard/Spring Boot apps):

--enable-native-access=ALL-UNNAMED

Modularized applications:

--enable-native-access=org.newsclub.net.unix

See junixsocket Compatibility Considerations for more information.

Development Notes

consul-client makes use of Immutables to generate code for many of the value classes. This provides a lot of functionality and benefit for little code, but it does require some additional development setup.

Official instructions are here, although you may want to change the target directories to the more gradle-like "generated/source/apt/main" and "generated/source/apt/test" targets.

Integration Tests

Runs consul with Testcontainers

About

A Consul Client for Java

Topics

Resources

Stars

15 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages