Discovery overview
Ce contenu n’est pas encore disponible dans votre langue.
“Discovery” in actor-ts covers two separate concerns:
| Concern | Mechanism | When |
|---|---|---|
| Cluster bootstrap | Seed providers | Once at node startup — how this node finds its peers. |
| Runtime service lookup | Receptionist | While 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
Section titled “Seed providers”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:
| Provider | Use |
|---|---|
ConfigSeedProvider | Static list from env vars / config. |
DnsSeedProvider | DNS SRV-record resolution. |
KubernetesApiSeedProvider | Live pod listing via the K8s API. |
AggregateSeedProvider | Chain multiple providers with fallback. |
Pick by your deployment environment:
- K8s →
KubernetesApiSeedProvider. - VMs with DNS-SD →
DnsSeedProvider. - Static deployment / Docker Compose →
ConfigSeedProvider. - Multi-environment / DR scenarios →
AggregateSeedProvider.
For most apps, you pick one provider, configure it once, and move on. See Joining and seeds for the full join protocol.
One lookup is not an answer
Section titled “One lookup is not an answer”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.
Receptionist
Section titled “Receptionist”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.
Seed providers vs receptionist
Section titled “Seed providers vs receptionist”| Question | Tool |
|---|---|
| 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.
When you might use both
Section titled “When you might use both”A typical K8s deployment:
// 1. Seed discovery — how this pod finds peers at startupconst 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 lookupconst 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.
Where to next
Section titled “Where to next”Seed providers
Section titled “Seed providers”- Config — static list.
- DNS — SRV / A records.
- Kubernetes API — pod listing.
- Aggregate — chain with fallback.
Receptionist
Section titled “Receptionist”- Receptionist — the service registry.
Related
Section titled “Related”- Joining and seeds — the join handshake that consumes seed providers.
- Cluster bootstrap — stable observation over a provider, plus initial-seed election.
- Cluster overview — the membership model underneath both.
