Skip to content

Service Discovery & Routing

This cookbook shows how to use a register collection for service discovery hints, route tables, and gateway-visible endpoint metadata.

When This Pattern Fits

Use this pattern when:

  • one logical key maps to one latest route value
  • reads should stay local and cheap
  • writers do not need multi-node merge semantics
  • the data is coordination metadata, not system-of-record business data

Typical examples:

  • gateway route hints
  • active upstream endpoint metadata
  • per-region ingress targets
  • collection type: REGISTER
  • locator example: shared/gateway/route-hints
  • entity type: immutable DsmEntity<E> record
  • persistence default: ephemeral

Mental Model

text
client request
    |
    v
gateway node
    |
    +--> local DsmRegister<RouteHint>.get("orders")
    |         |
    |         +--> 10.0.0.12:8443
    |
    +--> forward request to resolved upstream

control-plane update
    |
    v
routeHints.put(new RouteHint("orders", ..., "10.0.0.15:8443"))
    |
    v
runtime records local change
    |
    v
sync layer replicates delta to peer gateways

Entity Model

java
public record RouteHint(
        String entryKey,
        EntityMetadata metadata,
        String address)
        implements DsmEntity<RouteHint> {

    @Override
    public RouteHint withMetadata(EntityMetadata metadata) {
        return new RouteHint(entryKey, metadata, address);
    }
}

Use the route name, upstream logical name, or shard key as entryKey().

Registration Pattern

java
DsmRegister<RouteHint> routeHints = runtime.register(
    CollectionSpecBuilder.<RouteHint>register(
            "shared",
            "gateway",
            "route-hints")
        .schemaId("route-hints/v1")
        .codec(new RouteHintCodec())
        .build());

Read/Write Pattern

java
routeHints.put(new RouteHint("orders", null, "10.0.0.12:8443"));

Optional<RouteHint> hint = routeHints.get("orders");
List<RouteHint> snapshot = routeHints.all();

Operational Flow

text
node-a put(route-hint)
    |
    +--> local register updated
    |
    +--> metadata stamped by runtime
    |
    +--> steady-state delta replication
    |
    +--> lagging peers repaired by replay or snapshot

Design Rules

  • keep values small and routing-oriented
  • do not store large endpoint catalogs or heavy health details in DSM entities
  • prefer one route hint collection per application domain instead of one giant mixed-purpose register
  • change schemaId when route payload semantics change incompatibly

Common Mistakes

Using A Register For Ownership

If the real question is "which worker currently owns shard-17", this should be a lease collection, not a register.

Storing Primary Service Data

Route hints are coordination metadata. Do not treat DSM as the source of truth for customer or order data.

Overloading One Collection

Do not mix unrelated routing, feature flags, and operational toggles into one collection just because they are all "metadata".

Spring Boot Shape

yaml
dsm:
  collections:
    - bean-name: routeHintsCollection
      tenant-id: shared
      application-id: gateway
      collection-id: route-hints
      schema-id: route-hints/v1
      type: REGISTER
      consistency-tier: REGISTER
      codec-bean: routeHintCodec