Contents
Overview
In Helidon, discovery is the general process of finding named sets of advertised resources at a moment of an application’s runtime. The advertised resources are often URIs representing microservice endpoints. In some environments, those endpoints might frequently come and go at unpredictable intervals, as microservices are started, stopped, and redeployed. The named applications they represent, however, are relatively static. Discovery helps link such a named application to its transient resources, so that clients can more easily contact it, knowing only its name.
Helidon Discovery is a feature with a vendor- and implementation-independent API backed by vendor-specific implementations of that API known as providers. A developer programs against the Discovery API, and packages a (normally Helidon-supplied) conformant Discovery implementation (a provider) with her application at deployment time. See Providers below.
Maven Coordinates
To enable Helidon Discovery, add the following dependency to your project’s pom.xml (see Managing Dependencies).
pom.xml<dependencies>
<dependency>
<groupId>io.helidon.discovery</groupId>
<artifactId>helidon-discovery</artifactId>
</dependency>
</dependencies>- Helidon Discovery API dependency.
Discovery is implemented by one or more discovery providers. Generally you will choose a single provider and include its relevant dependencies on your runtime classpath as well. See the Providers section for more details.
API Usage
To use Helidon Discovery, you acquire an io.helidon.discovery.Discovery object and call its uris(String, URI) method to find resources represented as io.helidon.discovery.DiscoveredUri instances. You supply a discovery name, which is the name under which you expect to find advertised resources, and a default value, which is a URI to use in case the provider does not supply any resources. In general, DiscoveredUris you receive are ordered from more suitable to less suitable, where the definition of suitable is up to the provider. Some providers will consider aspects like the health or uptime of an advertised resource when returning results. Others may not. Finally, a DiscoveredUri representing the default value you supply will always be present as the last element in the set of resources you receive.
Discovery Acquisition
Discovery Acquisition Using Helidon Inject
You can acquire a io.helidon.discovery.Discovery object by injecting it into your Helidon SE application:
Discovery object using Helidon Injectimport java.util.Objects;
import io.helidon.discovery.Discovery;
import io.helidon.service.registry.Service;
public class MyClass {
private final Discovery discovery;
@Service.Inject
public MyClass(Discovery discovery) {
this.discovery = Objects.requireNonNull(discovery, "discovery");
}
}- Use the
io.helidon.service.registry.Service.Injectannotation to indicate that this constructor has an injection point. - Here, the
discoveryconstructor parameter is the injection point and will receive a non-nullinstance ofio.helidon.discovery.Discovery. - The constructor explicitly assigns the injected reference to the
discoveryinstance field.
Discovery Acquisition Using the Helidon Service Registry
You can acquire a io.helidon.discovery.Discovery object by using the Helidon Service Registry via the io.helidon.service.registry.Services façade:
Discovery object using the Helidon Service Registryimport io.helidon.discovery.Discovery;
import io.helidon.service.registry.Services;
public class MyOtherClass {
private final Discovery discovery;
public MyOtherClass() {
this.discovery = Services.get(Discovery.class);
}
}- Use the
io.helidon.service.registry.Services#get(Class)method to acquire an instance of theio.helidon.discovery.Discoveryclass, and assign it to an instance field.
Discovering URIs
Discovery uses a discovery name to identify and discover URIs notionally belonging to an application. An application may have several URIs. The discovery name is the name that identifies the application for discovery purposes.
To discover a named application’s URIs, call the Discovery#uris(String, URI) method, passing it the discovery name and a URI to use as a default value. Both values must be non-null. You will receive an immutable SequencedSet of io.helidon.discovery.DiscoveredUri instances representing the URIs, ordered from the most to the least suitable, according to the provider. A DiscoveredUri representing the default value will appear last in the set:
import java.net.URI;
import java.util.SequencedSet;
import io.helidon.discovery.DiscoveredUri;
import io.helidon.discovery.Discovery;
SequencedSet<DiscoveredUri> uris =
discovery.uris("EXAMPLE",
URI.create("http://example.com/"));
URI uri = uris.getFirst().uri(); - URIs that are discovered are represented as a
SequencedSetofio.helidon.discovery.DiscoveredUriinstances. This is the discovered set. In general, the first element in the set is the discovered URI that is the most suitable, as determined by the Discovery provider. (The last element is aDiscoveredUriwhoseuri()method yields aURIthat is identical or equal to theURIthat was supplied as the default value.) EXAMPLEis the discovery name for which URIs are being sought.- This
URIis a default value in case the Discovery provider finds no URIs, or encounters an error. ADiscoveredUrirepresenting it will appear last in the discovered set. - This
URIis the most suitable one for use, and may or may not be equal to the supplied default value.
Providers
The Discovery API is implemented at runtime by a Discovery provider. Helidon currently ships with a Eureka Discovery provider. Others may follow in the future.
To use a Discovery provider, include it on your runtime classpath. See the provider’s documentation for details about installing, configuring, and using the provider.
Eureka
The Helidon Eureka Discovery provider implements the Discovery API at runtime by communicating with a Netflix Eureka server (version 2.0.5 or later).
Maven Coordinates
To use the Helidon Eureka Discovery provider, add the following dependency to your project’s pom.xml (see Managing Dependencies).
pom.xml<dependencies>
<dependency>
<groupId>io.helidon.discovery.providers</groupId>
<artifactId>helidon-discovery-providers-eureka</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>- Helidon Eureka Discovery provider dependency.
- The scope for the provider. Use
runtimeif you have no interest in provider-specific classes and methods (the most common case). Usecompileif you plan to call provider-specific methods.
Configuration
The Helidon Eureka Discovery provider can be configured using Helidon Config. Examples shown below are in YAML, but are expressible in any format and any location that Helidon Config supports.
Configuration for the Helidon Eureka Discovery provider is found under a top-level discovery.eureka key path.
Generated documentation normatively describing the provider’s configuration in full can be found in Helidon’s Configuration Reference. Some common usages and examples are detailed below.
Configuring the Location of the Eureka Server
In order for the Helidon Eureka Discovery provider to do any meaningful work, you must tell it where the Eureka server is. (Discovery cannot bootstrap itself!) This is the only configuration that is effectively required. (If it is omitted, no error will occur, but the provider will log a message and effectively do nothing.)
To do this, you specify attributes about the internal HTTP client it uses, specifically its base-uri property:
application.yamldiscovery:
eureka:
client:
base-uri: "http://example.com:8761/eureka" discoveryis the topmost key of the provider’s logical configuration tree.eurekais the configuration name of the Helidon Eureka Discovery provider.clientidentifies HTTP client configuration.base-uriis a property of the HTTP client identifying the location of a Netflix Eureka server (version 2.0.5 or later). Eureka servers are normally hosted on port8761.
Configuring Caching
The Helidon Eureka Discovery provider uses a local cache of discovered URIs by default. You can configure, among other things:
whether the cache is enabled
how often the cache refreshes
whether the cache is computed or fully replaced
application.yamldiscovery:
eureka:
cache:
compute-changes: true
defer-sync: false
enabled: true
fetch-thread-name: "Eureka registry fetch thread"
sync-interval: "PT30S" discoveryis the topmost key of the provider’s logical configuration tree.eurekais the configuration name of the Helidon Eureka Discovery provider.cacheidentifies configuration related to the local cache of Eureka-supplied information.compute-changescontrols how the cache’s content is determined: iftrue, by applying a series of changes against an initial state; iffalse, by replacing the contents of the cache with a new copy.trueby default.defer-synccontrols whether the cache should be synchronized as late as possible (true), or as early as possible (false).falseby default.enabledcontrols whether the cache is enabled. Iffalse, then none of the other configuration items in thecachetree are relevant, and every invocation of theDiscovery#uris(String, URI)method will result in a network call.fetch-thread-namecontains the name of the thread that synchronizes the cache.Eureka registry fetch threadby default.sync-intervalcontrols the time between synchronizations of the cache.PT30S(30 seconds) by default.
Configuring IP Address vs. Hostname
The Helidon Eureka Discovery provider can be configured to prefer IP addresses in URIs when possible (instead of hostnames).
application.yamldiscovery:
eureka:
preferIpAddress: false discoveryis the topmost key of the provider’s logical configuration tree.eurekais the configuration name of the Helidon Eureka Discovery provider.preferIpAddresscontrols whether the host component of a URI should use an IP address, when possible (true), or a hostname (false).falseby default.
Disabling the Provider
In some testing scenarios, it may be useful to disable the Helidon Eureka Discovery provider entirely. (When any Discovery provider is disabled, only default values supplied to the Discovery#uris(String, URI) method will be returned.)
application.yamldiscovery:
eureka:
enabled: false discoveryis the topmost key of the provider’s logical configuration tree.eurekais the configuration name of the Helidon Eureka Discovery provider.enabledcontrols whether the provider is enabled at all (true) or completely disabled (false), in which case all other configuration pertaining to it is irrelevant.trueby default.
Related Documentation
Users of the Helidon Eureka Discovery provider may also be interested in the (related) Eureka Server Service Instance Registration feature.
Integrations
Helidon integrates a Discovery provider with other Helidon modules as described below.
Web Client Discovery Integration
Helidon integrates a Discovery provider with Web Client.
Maven Coordinates
To include the Helidon Web Client Discovery integration in your project, you add the Web Client Discovery integration dependency as well as a Discovery provider dependency (see Managing Dependencies):
pom.xml<dependencies>
<dependency>
<groupId>io.helidon.webclient</groupId>
<artifactId>helidon-webclient-discovery</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.helidon.discovery.providers</groupId>
<artifactId>helidon-discovery-providers-eureka</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>- Helidon Web Client Discovery integration dependency.
- The scope for the integration.
runtimesince the integration is never required at compile time. - Helidon Eureka Discovery provider dependency (for example).
- The scope for the provider. Use
runtimeif you have no interest in provider-specific classes and methods (the most common case). Usecompileif you plan to call provider-specific methods.
The behavior of the Web Client Discovery integration is fully specified and documented.
Configuration
The Helidon Web Client Discovery integration can be configured using Helidon Config. Examples shown below are in YAML, but are expressible in any format and any location that Helidon Config supports.
Because the Helidon Web Client Discovery integration is fundamentally a Web Client Service, you configure it under a Web Client’s services configuration node:
application.yamlwebclient:
services:
discovery: - Indicates that the Web Client Discovery integration should apply to this Web Client configuration. More configuration is required; see below.
You also configure the Discovery provider in use following its documentation. See, for example, Eureka configuration.
Configuring URIs
To mark URIs requested by a Web Client as subject to discovery, and to use discovery names appropriate for them, you need to configure prefix URIs. URIs that match no prefix will not be subject to discovery:
application.yamlwebclient:
services:
discovery:
prefix-uris:
EXAMPLE: "https://example.com:443/"
TEST: "https://test.example.com:443/" - Indicates that URIs starting with
https://example.com:443/will be subject to discovery, using the discovery name ofEXAMPLE - Indicates that URIs starting with
https://test.example.com:443/will be subject to discovery, using the discovery name ofTEST - URIs that begin with text other than
https://example.com:443/orhttps://test.example.com:443/will not be subject to discovery