Zum Inhalt springen
Deutsch

Spawn Typed

Ein Behavior<T> ist ein Wert. Um ihn in die Runtime zu bringen — um eine tatsächliche ActorRef<T> zu bekommen, der du Nachrichten tellen kannst — verwende die Methode auf dem Host, von dem aus du spawnst:

WoMethode
Außerhalb eines Actorssystem.spawnTyped(behavior, name) / system.spawnTypedAnonymous(behavior)
Innerhalb eines untyped Actor.onReceivethis.context.spawnTyped(behavior, name) / this.context.spawnTypedAnonymous(behavior)
Innerhalb eines typed Behaviors.setup / Handlerscontext.spawn(behavior, name)
Überall, wo eine Actor-Klasse oder Factory akzeptiert wirdtypedActor(behavior)

Die Methoden-Form spiegelt die Standard-OO-API — spawn vs. spawnAnonymous je nachdem, ob du einen Namen angibst.

import { match } from 'ts-pattern';
import { ActorSystem, Behaviors, type Behavior, type ActorRef } from 'actor-ts';
type IncrementCommand = { kind: 'increment' };
type GetCommand = { kind: 'get'; replyTo: ActorRef<number> };
type Command = IncrementCommand | GetCommand;
const counter = (n: number): Behavior<Command> => Behaviors.receive((context, command) =>
match(command)
.with({ kind: 'increment' }, () => counter(n + 1))
.with({ kind: 'get' }, (c) => { c.replyTo.tell(n); return Behaviors.same; })
.exhaustive());
const system = ActorSystem.create('demo');
const ref = system.spawnTyped(counter(0), 'counter');
// ^- ActorRef<Command>

Die Signaturen:

class ActorSystem {
spawnTyped<T>(behavior: Behavior<T>, name: string): ActorRef<T>;
spawnTypedAnonymous<T>(behavior: Behavior<T>): ActorRef<T>;
}

Gibt eine typisierte ActorRef<T> zurück — tell akzeptiert nur Command-förmige Nachrichten, der Compiler erzwingt das.

ctx.spawnTyped — typed Child von einem untyped Parent

Abschnitt betitelt „ctx.spawnTyped — typed Child von einem untyped Parent“
import { Actor, Behaviors } from 'actor-ts';
class UntypedParent extends Actor<...> {
override preStart(): void {
const typedChild = this.context.spawnTyped(counter(0), 'child');
// typedChild: ActorRef<Command>
typedChild.tell({ kind: 'increment' });
}
}

Die Signaturen leben auf ActorContext:

interface ActorContext {
spawnTyped<T>(behavior: Behavior<T>, name: string): ActorRef<T>;
spawnTypedAnonymous<T>(behavior: Behavior<T>): ActorRef<T>;
}

Nützlich, wenn du einen bestehenden untyped-Supervisor hast, der typisierte Workers spawnen muss. Das Kind ist ein normaler Eintrag in der Children-Liste des Parents — Supervisor-Strategien gelten nach der Strategie des Parents, Death Watch funktioniert in beide Richtungen.

typedActor — Interop mit der Klassen-oder-Factory-API

Abschnitt betitelt „typedActor — Interop mit der Klassen-oder-Factory-API“
import { ActorOptions, typedActor } from 'actor-ts';
const counterActor = typedActor(counter(0));
const counterOptions = ActorOptions.create<Command>()
.withMailboxCapacity(500)
.withDispatcher(myDispatcher);
const ref = system.spawn(counterActor, 'counter', counterOptions);

Wenn du ein typisiertes Behavior willst, die API aber einen Actor nimmt — ein Einstiegspunkt, der älter ist als die typisierte Schicht, oder ein Spawn, der eigene ActorOptions braucht —, gibt typedActor(behavior) die ActorFactory<T> zurück, die diese Stellen akzeptieren.

Die Form:

function typedActor<T>(behavior: Behavior<T>): ActorFactory<T>;

Die zurückgegebene Factory kann überall übergeben werden, wo ein Actor erwartet wird — system.spawn, context.spawn, ClusterSingleton.start, der entityActor-Slot der Sharding-Region.

Innerhalb eines typisierten Handlers exponiert der Context sein eigenes spawn:

const parent: Behavior<ParentMessage> = Behaviors.setup((context) => {
const child = context.spawn(workerBehavior, 'worker');
// ^- ActorRef<WorkerMessage>
return Behaviors.receive((context, message) => {
child.tell({ kind: 'do-it' });
return Behaviors.same;
});
});

Das ist der Standard-Weg für typed-Parents, typed-Children zu spawnen — durchgehend typisiert. context.spawn(behavior) kennt den Nachrichtentyp des Kindes aus dem Typ-Parameter des Behaviors.

Für die deterministischen Varianten (spawnTyped) ist der name-Parameter Pflicht und muss unter Geschwistern eindeutig sein. Für spawnTypedAnonymous generiert das Framework einen — $anonymous-, einen Zähler pro Elternteil und zwölf zufällige Hex-Zeichen, zum Beispiel '$anonymous-1-3f9c1a0d7b42'. Der Suffix ist zufällig, der Pfad also über Läufe hinweg nicht stabil; nutze spawnTyped, wenn du den Actor über den Pfad adressieren musst.

Der Pfad des resultierenden Actors folgt dem Standardformat:

  • system.spawnTyped(b, 'counter')actor-ts://my-app/user/counter
  • parentContext.spawnTyped(b, 'worker')actor-ts://my-app/user/<parent>/worker
  • context.spawn(b, 'worker')actor-ts://my-app/user/<parent>/worker

Siehe Actor-Pfade für die Pfad-Semantik.

Aufrufer ist außerhalb eines Actors:
→ system.spawnTyped(b, name) // mit Namen
→ system.spawnTypedAnonymous(b) // wegwerf
Aufrufer ist innerhalb eines untyped Actor.onReceive:
→ this.context.spawnTyped(b, name)
→ this.context.spawnTypedAnonymous(b)
Aufrufer ist innerhalb eines typed Behaviors.setup oder Handlers:
→ context.spawn(b, name)
Du hast eine Funktion, die einen Actor nimmt, und willst ein Behavior verwenden:
→ typedActor(b)

Die Methoden sind absichtlich klein — jede handhabt einen häufigen Fall. typedActor ist die Notluke, wenn du ein Behavior in Actor-förmige APIs stecken musst.

  • Behaviors — das DSL, das die Werte produziert, die du diesen Methoden übergibst.
  • Typed Actor — die Runtime, die die Spawn-Methoden wickeln.
  • Actors erzeugen — die untyped Konfiguration, die typedActor zurückgibt.
  • Actor-System — die spawn-API, die die Methoden letztlich aufrufen.