Zum Inhalt springen
Deutsch

Cluster-Client

ClusterClient lässt einen Prozess außerhalb des Clusters mit Actors innerhalb sprechen. Der externe Prozess ist kein Cluster-Mitglied — kein Gossip, kein Mitgliedschaftsstatus — aber er kann cluster-interne Actors per bekannten Receptionist-Kontakten mit tell und ask ansprechen.

import { ClusterClient } from 'actor-ts';
const client = ClusterClient.create({
contacts: ['actor-ts://my-app@10.0.0.5:2552/system/receptionist'],
});
// Senden an einen bekannten Cluster-Actor:
client.send('/user/api/orders', { kind: 'place', ... });
// Oder über Receptionist per Service-Key:
client.sendByKey(ServiceKey.of<ApiMsg>('api'), { kind: 'list-orders' });

Drei legitime Anwendungsfälle:

  1. Externe Services, die nicht in den Actor-Cluster gehören, aber mit ihm reden müssen — ein Python-ML-Service, der an einen Kafka-Actor innerhalb des Clusters postet.
  2. Mobile-/Desktop-Clients über eine Bridge — eine serverseitige Bridge hält einen ClusterClient + bietet eine REST/WS-API nach außen.
  3. Cross-Cluster-Föderation — zwei Cluster, bei denen einer mit bestimmten Actors im anderen sprechen muss, ohne zu mergen.

Für typische Setups ist alles Teil des Clusters — ClusterClient ist der Notausgang für Fälle, in denen das nicht möglich ist.

ClusterExterner ProzessClusterExterner Prozesskontaktiere Cluster-Receptionist über bekannten Pfadbekannte Service-Refsschicke Nachrichten an Refs

Der Client:

  1. Verbindet sich mit einem oder mehreren Kontakten (bekannte Cluster-Nodes, auf denen ein ClusterClientReceptionist läuft).
  2. Entdeckt verfügbare Services über den Receptionist.
  3. Routet Nachrichten zu den richtigen Actors.
  4. Behandelt Failover, wenn Kontakte unerreichbar werden — verbindet sich zu einem anderen.
interface ClusterClientSettings {
contacts: string[]; // mindestens ein Cluster-Node-Pfad
reconnectIntervalMs?: number;
acceptableHeartbeatPauseMs?: number;
}

contacts ist die Liste der Receptionist-Pfade. Der Client wählt zufällig einen aus, um sich zu verbinden; bei Ausfall fällt er auf andere zurück.

Für stabile Kontaktadressen deployt die Cluster-Seite typisch einen ClusterClientReceptionist auf einem festen Pod (oder sharded Set) an einem bekannten Pfad.

import { ClusterClientReceptionist } from 'actor-ts';
system.spawn(
ClusterClientReceptionist.props({
cluster,
role: 'frontend', // optional — auf bestimmte Nodes beschränken
}),
'cluster-client-receptionist',
);

Der Receptionist legt registrierte Services für externe Clients offen. Actors registrieren:

const receptionistRef = system.actorSelection('/user/cluster-client-receptionist');
receptionistRef.tell({
kind: 'register-service',
key: ServiceKey.of<OrdersMsg>('orders'),
ref: ordersActor,
});

Externe Clients können dann sendByKey('orders', msg) machen.

// Innerhalb des Clusters — Actors sprechen direkt:
const ref = await system.actorSelection('actor-ts://my-app@host:2552/user/api').resolveOne();
ref.tell(...);
// Außerhalb des Clusters — ClusterClient:
const client = ClusterClient.create({ contacts: [...] });
client.send('/user/api', ...);

Unterschiede:

  • Innen: erfordert Cluster-Mitgliedschaft. Refs propagieren per Gossip; du kannst langlebige Refs halten.
  • ClusterClient: keine Mitgliedschaft; Refs werden pro Nachricht über den Receptionist aufgelöst.