or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

core-api.mddiscovery-extension.mdindex.mdresolution-types.md
tile.json

resolution-types.mddocs/

Resolution Data Types

Data structures representing service discovery results including resolved endpoints with host, port, and IP address information. These types encapsulate the results of service discovery operations and provide both Scala and Java APIs for accessing the resolved service endpoints.

Capabilities

Resolved Result Class

Container for service discovery results, holding the service name and a collection of resolved service endpoints.

/**
 * Result of a successful service discovery lookup
 * @param serviceName The service name that was looked up
 * @param addresses Sequence of resolved service endpoints
 */
final class Resolved(val serviceName: String, val addresses: immutable.Seq[ResolvedTarget]) {
  /**
   * Java API: Get the resolved addresses as a Java List
   * @return List of ResolvedTarget instances
   */
  def getAddresses: java.util.List[ResolvedTarget]
  
  /**
   * String representation for debugging
   * @return String in format "Resolved(serviceName,addresses)"
   */
  override def toString: String
  
  /**
   * Equality comparison based on service name and addresses
   * @param obj Object to compare with
   * @return true if equal, false otherwise
   */
  override def equals(obj: Any): Boolean
  
  /**
   * Hash code based on service name and addresses
   * @return Hash code value
   */
  override def hashCode(): Int
}

Usage Examples:

import akka.discovery.ServiceDiscovery.{Resolved, ResolvedTarget}
import scala.collection.immutable

// Creating Resolved instances (typically done by discovery implementations)
val targets = immutable.Seq(
  ResolvedTarget("service1.local", Some(8080), None),
  ResolvedTarget("service2.local", Some(8080), None)
)
val resolved = Resolved("my-service", targets)

// Accessing results
println(s"Service: ${resolved.serviceName}")
println(s"Found ${resolved.addresses.length} endpoints")

resolved.addresses.foreach { target =>
  println(s"Host: ${target.host}, Port: ${target.port}")
}
import akka.discovery.ServiceDiscovery;
import java.util.List;

// Processing results from service discovery (Java API)
CompletionStage<ServiceDiscovery.Resolved> futureResolved = 
    serviceDiscovery.lookup("my-service", Duration.ofSeconds(3));

futureResolved.thenAccept(resolved -> {
    System.out.println("Service: " + resolved.serviceName());
    
    List<ServiceDiscovery.ResolvedTarget> addresses = resolved.getAddresses();
    System.out.println("Found " + addresses.size() + " endpoints");
    
    addresses.forEach(target -> {
        System.out.println("Host: " + target.host() + 
                          ", Port: " + target.getPort().orElse(-1));
    });
});

ResolvedTarget Endpoint Class

Represents an individual service endpoint with host, optional port, and optional IP address information.

/**
 * Individual resolved service endpoint
 * @param host Hostname or IP address string
 * @param port Optional port number
 * @param address Optional resolved IP address (used for cluster bootstrap)
 */
final class ResolvedTarget(val host: String, val port: Option[Int], val address: Option[InetAddress]) {
  /**
   * Java API: Get the port number
   * @return Optional containing port if available
   */
  def getPort: Optional[Int]
  
  /**
   * Java API: Get the IP address
   * @return Optional containing InetAddress if available
   */
  def getAddress: Optional[InetAddress]
  
  /**
   * String representation for debugging
   * @return String in format "ResolvedTarget(host,port,address)"
   */
  override def toString: String
  
  /**
   * Equality comparison based on host, port, and address
   * @param obj Object to compare with
   * @return true if equal, false otherwise
   */
  override def equals(obj: Any): Boolean
  
  /**
   * Hash code based on host, port, and address
   * @return Hash code value
   */
  override def hashCode(): Int
}

Usage Examples:

import akka.discovery.ServiceDiscovery.ResolvedTarget
import java.net.InetAddress

// Different ways to create ResolvedTarget instances
val basicTarget = ResolvedTarget("api.example.com", None, None)
val withPort = ResolvedTarget("api.example.com", Some(8080), None)
val withIPAddress = ResolvedTarget("api.example.com", Some(8080), Some(InetAddress.getByName("192.168.1.100")))

// Accessing target information
println(s"Host: ${withIPAddress.host}")
println(s"Port: ${withIPAddress.port.getOrElse("not specified")}")
println(s"IP: ${withIPAddress.address.map(_.getHostAddress).getOrElse("not resolved")}")

// Pattern matching on targets
withIPAddress.port match {
  case Some(port) => println(s"Service available on port $port")
  case None => println("No specific port information")
}
import akka.discovery.ServiceDiscovery;
import java.net.InetAddress;
import java.util.Optional;

// Processing individual targets (Java API)
ServiceDiscovery.ResolvedTarget target = /* obtained from Resolved.getAddresses() */;

System.out.println("Host: " + target.host());

Optional<Integer> port = target.getPort();
if (port.isPresent()) {
    System.out.println("Port: " + port.get());
} else {
    System.out.println("No port specified");
}

Optional<InetAddress> address = target.getAddress();
if (address.isPresent()) {
    System.out.println("IP: " + address.get().getHostAddress());
} else {
    System.out.println("IP not resolved");
}

Factory Objects

Companion objects providing factory methods and utilities for creating result instances.

/**
 * Factory methods for creating Resolved instances
 */
object Resolved {
  /**
   * Create a Resolved instance
   * @param serviceName Service name that was looked up
   * @param addresses Sequence of resolved endpoints
   * @return Resolved instance
   */
  def apply(serviceName: String, addresses: immutable.Seq[ResolvedTarget]): Resolved
  
  /**
   * Pattern matching extractor
   * @param resolved Resolved instance to extract from
   * @return Option containing service name and addresses tuple
   */
  def unapply(resolved: Resolved): Option[(String, immutable.Seq[ResolvedTarget])]
}

/**
 * Factory methods and utilities for ResolvedTarget
 */
object ResolvedTarget {
  /**
   * Create a ResolvedTarget instance
   * @param host Hostname or IP address
   * @param port Optional port number
   * @param address Optional IP address
   * @return ResolvedTarget instance
   */
  def apply(host: String, port: Option[Int], address: Option[InetAddress]): ResolvedTarget
  
  /**
   * Implicit ordering for ResolvedTarget instances
   * Orders by IP address first, then hostname, then port number for consistent sorting.
   * This ensures deterministic ordering when multiple endpoints are returned.
   */
  implicit val addressOrdering: Ordering[ResolvedTarget]
}

Usage Examples:

import akka.discovery.ServiceDiscovery.{Resolved, ResolvedTarget}
import scala.collection.immutable

// Using factory methods
val target1 = ResolvedTarget("host1.local", Some(8080), None)
val target2 = ResolvedTarget("host2.local", Some(8080), None)
val resolved = Resolved("my-service", immutable.Seq(target1, target2))

// Pattern matching with unapply
resolved match {
  case Resolved(serviceName, addresses) =>
    println(s"Found service '$serviceName' with ${addresses.length} addresses")
  case _ =>
    println("Unexpected result type")
}

// Sorting targets using implicit ordering
val sortedTargets = resolved.addresses.sorted
println("Targets in sorted order:")
sortedTargets.foreach(println)

Integration with Service Discovery

These types are returned by all service discovery implementations and provide consistent access patterns:

import akka.discovery.{Discovery, Lookup}
import scala.concurrent.Future

// All discovery methods return these same types
val serviceDiscovery = Discovery(system).discovery

// Basic lookup returns Resolved
val basicResult: Future[Resolved] = serviceDiscovery.lookup("web-service", 3.seconds)

// Advanced lookup also returns Resolved
val advancedLookup = Lookup("web-service").withPortName("http").withProtocol("tcp")
val advancedResult: Future[Resolved] = serviceDiscovery.lookup(advancedLookup, 3.seconds)

// Processing results is consistent regardless of discovery method
basicResult.foreach { resolved =>
  println(s"Service '${resolved.serviceName}' resolved to:")
  resolved.addresses.foreach { target =>
    val portInfo = target.port.map(p => s":$p").getOrElse("")
    val ipInfo = target.address.map(ip => s" (${ip.getHostAddress})").getOrElse("")
    println(s"  ${target.host}$portInfo$ipInfo")
  }
}

Empty Results

Service discovery may return empty results when no endpoints are found:

import akka.discovery.ServiceDiscovery.{Resolved, ResolvedTarget}
import scala.collection.immutable

// Empty result (no endpoints found)
val emptyResult = Resolved("non-existent-service", immutable.Seq.empty[ResolvedTarget])

// Checking for empty results
serviceDiscovery.lookup("some-service", 3.seconds).foreach { resolved =>
  if (resolved.addresses.isEmpty) {
    println(s"No endpoints found for service '${resolved.serviceName}'")
  } else {
    println(s"Found ${resolved.addresses.length} endpoints")
  }
}