Skip to content

Concepts#

This page presents the concepts used in Stork. When using Stork in a managed environment, such as Quarkus, all these concepts are hidden, as you only configure the lookup and selection. However, when using the programmatic API, you will use these concepts directly.

concepts concepts

Process overview#

When using the programmatic API of Stork, you can:

  1. Retrieve the singleton Stork instance. This instance is configured with the set of Service it manages.
  2. Retrieve the Service you want to use. Each Service is associated with a name.
  3. Retrieve the ServiceInstance which will provide the metadata to access the actual service.

service discovery and selection service discovery and selection

Behind the scenes, Stork will handle the service lookup and selection.

Note

The service lookup and selection are asynchronous operations. Thus, the API returns instances of Uni.

Stork#

io.smallrye.stork.Stork is the entry-point of the API. The Stork instance is a singleton. It needs to be initialized once (when the application starts) and shutdown when the application stops:

package examples;

import io.smallrye.stork.Stork;

public class StorkEntryPointExample {

    public static void main(String[] args) {
        Stork.initialize();
        Stork stork = Stork.getInstance();
        // ...
        Stork.shutdown();
    }

}

During the initialization, Stork looks for io.smallrye.stork.config.ConfigProvider SPI provider and CDI beans (from 2.x version) and retrieves the list of managed services:

  • A service is identified by a name.
  • A service has a service discovery configuration indicating how Stork will look for service instances
  • A service can have a load-balancer configuration indicating how Stork can select the most appropriate instance.

Service#

A io.smallrye.stork.Service is the structure representing a service used by the application. Services are pre-configured with their name, service discovery, and optionally, their load-balancer. You retrieve a Service using the Stork#getService(String name) method.

package examples;

import io.smallrye.stork.api.Service;
import io.smallrye.stork.Stork;

public class StorkServiceExample {

    public static void main(String[] args) {
        Stork.initialize();
        Stork stork = Stork.getInstance();

        Service service = stork.getService("my-service");

        // ...
        Stork.shutdown();
    }

}

The Service lets you retrieve the list of ServiceInstance, or select a single one, when a load-balancer is configured.

Service Instance#

The io.smallrye.stork.api.ServiceInstance represents an actual instance of the service. It provides the metadata to configure a client to interact with that specific instance of service.

package examples;

import java.time.Duration;
import java.util.List;

import io.smallrye.stork.Stork;
import io.smallrye.stork.api.Service;
import io.smallrye.stork.api.ServiceInstance;

public class StorkServiceLookupExample {

    public static void main(String[] args) {
        Stork.initialize();
        Stork stork = Stork.getInstance();

        Service service = stork.getService("my-service");
        List<ServiceInstance> instances = service.getInstances()
                .await().atMost(Duration.ofSeconds(5));

        // ...
        Stork.shutdown();
    }

}

The service selection is a two-steps process:

  1. Service lookup - using the service discovery
  2. Service selection - using the load balancer
package examples;

import java.time.Duration;

import io.smallrye.stork.Stork;
import io.smallrye.stork.api.Service;
import io.smallrye.stork.api.ServiceInstance;

public class StorkServiceSelectionExample {

    public static void main(String[] args) {
        Stork.initialize();
        Stork stork = Stork.getInstance();

        Service service = stork.getService("my-service");
        ServiceInstance instance = service.selectInstance()
                .await().atMost(Duration.ofSeconds(5));

        System.out.println(instance.getHost() + ":" + instance.getPort());

        // ...
        Stork.shutdown();
    }

}

Service Discovery#

The io.smallrye.stork.api.ServiceDiscovery represents a service discovery mechanism, such as DNS, Consul, or Eureka.

You can implement a custom service discovery for Stork by implementing the ServiceDiscoveryProvider interface. The corresponding ServiceRegistrarProviderLoader and RegistrarConfiguration classes will be automatically generated during compilation time.

Please note that the ServiceDiscovery implementation must be non-blocking.

Load Balancer#

The io.smallrye.stork.api.LoadBalancer represents a load-balancer strategy, such as round-robin.

To implement a custom load balancer for Stork, implement the LoadBalancerProvider interface. The corresponding LoadBalancerProviderLoader and Configuration classes will be automatically generated during compilation time.

Please note that the LoadBalancer implementation, similarly to ServiceDiscovery must be non-blocking.

Service registration#

The io.smallrye.stork.api.ServiceRegistrar represents a service registration mechanism for Consul and Eureka.

You can implement a custom service registrar for Stork by implementing the ServiceRegistrarProvider interface. The corresponding ServiceRegistrarProviderLoader and RegistrarConfiguration classes will be automatically generated during compilation time.

Please note that the ServiceRegistrar implementation must be non-blocking.