コンテンツにスキップ
日本語

Discovery overview

このコンテンツはまだ日本語訳がありません。

“Discovery” in actor-ts covers two separate concerns:

ConcernMechanismWhen
Cluster bootstrapSeed providersOnce at node startup — how this node finds its peers.
Runtime service lookupReceptionistWhile running — how actors find each other by service key.

They share the name “discovery” because they’re both lookup-based addressing, but the protocols and use cases are distinct.

Seed providers answer: “Which addresses should I try as cluster seeds at join time?”

import { Cluster, ClusterOptions, KubernetesApiSeedProvider, KubernetesApiSeedProviderOptions } from 'actor-ts';
const kubernetesApiSeedProviderOptions = KubernetesApiSeedProviderOptions.create()
.withNamespace('my-app')
.withServiceName('actor-ts')
.withSystemName('my-app')
.withPort(2552);
const provider = new KubernetesApiSeedProvider(
kubernetesApiSeedProviderOptions,
);
const addresses = await provider.lookup();
const seeds = addresses.map((address) => address.toString());
const clusterOptions = ClusterOptions.create()
.withHost(host)
.withPort(port)
.withSeeds(seeds);
await Cluster.join(system, clusterOptions);

Four providers ship:

ProviderUse
ConfigSeedProviderStatic list from env vars / config.
DnsSeedProviderDNS SRV-record resolution.
KubernetesApiSeedProviderLive pod listing via the K8s API.
AggregateSeedProviderChain multiple providers with fallback.

Pick by your deployment environment:

  • K8sKubernetesApiSeedProvider.
  • VMs with DNS-SDDnsSeedProvider.
  • Static deployment / Docker ComposeConfigSeedProvider.
  • Multi-environment / DR scenariosAggregateSeedProvider.

For most apps, you pick one provider, configure it once, and move on. See Joining and seeds for the full join protocol.

A provider returns whatever it can see right now. During a simultaneous start that is a different set on every node — DNS is mid-propagation, a pod is Ready before its IP is published, the K8s API paginates in a partial list — and a node that joins on the first answer forms a cluster out of its own partial view.

If your nodes start together with dynamic addresses, do not consume lookup() directly. Cluster bootstrap wraps any provider here: it polls until the returned set stops changing, then lets exactly one node form the cluster. The providers on this page stay exactly as they are — bootstrap is a phase on top of them, not a replacement.

The receptionist answers: “Which actors are registered under this service key, anywhere in the cluster?”

import { Find, ReceptionistId, Register, ServiceKey } from 'actor-ts';
// On node-A:
const receptionist = system.extension(ReceptionistId).start(cluster);
const key = ServiceKey.of<MyMessage>('my-service');
receptionist.tell(new Register(key, myActor));
// On node-B — Find replies with a Listing (its .refs are the matching
// actors across the cluster) to the actor you name as the reply target:
receptionist.tell(new Find(key, replyTo));

A cluster-wide service registry. Each node hosts a Receptionist actor; registrations are local-authoritative; peers learn about foreign registrations via gossip.

Use the receptionist when:

  • Actor location is dynamic — actors come and go, and consumers shouldn’t hard-code paths.
  • Multiple actors share a service — N workers all register under the same key; consumers see them all.
  • Cross-node discovery is needed — find an actor regardless of which node hosts it.

See Receptionist for the full API.

QuestionTool
How does THIS node find peers to join?Seed provider
How does an actor find another actor at runtime?Receptionist
How does an HTTP load balancer route requests to my pods?K8s Service (not this)
How does a service-mesh proxy discover backends?Service mesh (not this)

The framework’s discovery is for cluster internals. External service discovery (Consul, Eureka, service meshes) is your infrastructure’s concern; actor-ts gets its peer addresses from those at startup but otherwise doesn’t participate.

A typical K8s deployment:

// 1. Seed discovery — how this pod finds peers at startup
const kubernetesApiSeedProviderOptions = KubernetesApiSeedProviderOptions.create()
.withNamespace(process.env.K8S_NAMESPACE!)
.withServiceName('actor-ts')
.withSystemName('my-app')
.withPort(2552);
const addresses = await new KubernetesApiSeedProvider(
kubernetesApiSeedProviderOptions,
).lookup();
const seeds = addresses.map((address) => address.toString());
const clusterOptions = ClusterOptions.create()
.withHost(host)
.withPort(port)
.withSeeds(seeds);
await Cluster.join(system, clusterOptions);
// 2. Receptionist — for runtime actor lookup
const receptionist = system.extension(ReceptionistId).start(cluster);
// Register this pod's API actor:
receptionist.tell(new Register(
ServiceKey.of<ApiMessage>('api'),
system.spawn(ApiActor, 'api'),
));
// Other actors find it — the Listing is delivered to the reply target:
receptionist.tell(new Find(ServiceKey.of<ApiMessage>('api'), replyTo));

Seed providers run once; the receptionist runs continuously.