Skip to content

Discovery adapters

WorldDiscovery feeds routable World targets into Gateways. WorldRegistrar lets a World publish a renewable lease. Discovery is control plane state; Gateway requests still use direct ELR2 connections to the selected World.

DNS

DnsWorldDiscovery periodically resolves the host:port in DnsWorldDiscoveryConfig and replaces the target set for one region, realm, and route. It needs only the adapters feature.

Choose DNS for stable service names and Kubernetes headless Services. It is simple but exposes no per-instance metadata beyond resolved addresses.

Usage example

rust
use std::sync::Arc;

use elura::adapters::discovery::{DnsWorldDiscovery, DnsWorldDiscoveryConfig};
use elura::prelude::*;

let config = DnsWorldDiscoveryConfig::new("world.internal:18000", 1, 1);
let discovery = Arc::new(DnsWorldDiscovery::new(config)?);

let gateway = Gateway::new(gateway_config).world_discovery(discovery);

Replace only discovery when moving to Redis or Kubernetes; ELR2 routing and game handlers do not change.

Redis registration and discovery

RedisWorldRegistrar publishes expiring WorldRegistration leases; RedisWorldDiscovery scans and watches the same prefix. Enable redis and use matching RedisWorldRegistrationConfig.key_prefix and RedisWorldDiscoveryConfig.key_prefix.

The registration TTL must be at least twice the renewal interval. Every World needs a unique ID and an address reachable from all Gateways. Standalone and Cluster constructors are available where supported.

Usage example

Use the same prefix on the World and Gateway sides. The World publishes its lease; the Gateway watches the resulting target set.

rust
use std::sync::Arc;

use elura::adapters::discovery::{
    RedisWorldDiscovery, RedisWorldDiscoveryConfig,
    RedisWorldRegistrar, RedisWorldRegistrationConfig,
};
use elura::prelude::*;

let registration = RedisWorldRegistrationConfig::new(
    "game:worlds",
    "world-1.internal:18000",
    1,
    1,
);
let registrar = Arc::new(
    RedisWorldRegistrar::connect(redis_url, "world-1", registration).await?,
);
let world = World::new(world_config).registrar(registrar);

let discovery = Arc::new(
    RedisWorldDiscovery::connect(
        redis_url,
        RedisWorldDiscoveryConfig::new("game:worlds"),
    )
    .await?,
);
let gateway = Gateway::new(gateway_config).world_discovery(discovery);

World::run supervises registration renewal and cleanup. Gateway::run supervises discovery refresh and subscription recovery.

Kubernetes Endpoints

EndpointDiscovery performs a one-shot EndpointSlice resolution. EndpointWatcher continuously watches slices and updates routes; KubernetesWorldDiscovery wraps that watcher as the higher-level Gateway integration. Enable kubernetes and grant the process read/watch access only to the required namespace and resources.

Choose the Kubernetes watcher when API-driven convergence or endpoint metadata is worth the additional credentials and control-plane dependency.

Usage example

rust
use std::sync::Arc;

use elura::adapters::discovery::KubernetesWorldDiscovery;
use elura::adapters::kubernetes::EndpointWatcherConfig;
use elura::prelude::*;

let watcher = EndpointWatcherConfig::new("game", "world", "elr2", 1, 1);
let discovery = Arc::new(KubernetesWorldDiscovery::new(watcher)?);
let gateway = Gateway::new(gateway_config).world_discovery(discovery);

The world Service must expose a port named elr2. The Gateway service account needs get, list, and watch permission for EndpointSlices in the game namespace.

Choosing

EnvironmentUsually start with
Single process or fixed targetsStatic application configuration
VM/bare metal with service DNSDNS
VM/bare metal needing per-World leasesRedis registration/discovery
Kubernetes with simple service routingDNS/headless Service
Kubernetes needing direct EndpointSlice updatesKubernetes watcher

Applications may implement WorldDiscovery and WorldRegistrar for Consul, etcd, a platform control plane, or another registry.

Released under the MIT License.