Zum Inhalt springen

Prozessverwaltung

Kindprozesse spawnen, überwachen und mit ihnen kommunizieren. Implementiert Actor-Modell-Muster mit Nachrichtenübergabe, Supervision und Lebenszyklusverwaltung.

Die globale Variable process ist immer verfügbar — sie erfordert kein require() und muss nicht in modules: aufgeführt werden.

Die aktuelle Frame-ID oder Prozess-ID abrufen:

local frame_id = process.id() -- Aufrufkettenidentifikator
local pid = process.pid() -- Prozess-ID

Nachricht(en) an einen Prozess per PID oder registriertem Namen senden:

local ok, err = process.send(destination, topic, ...)
ParameterTypBeschreibung
destinationstringPID oder registrierter Name
topicstringTopic-Name (darf nicht mit @ beginnen)
...anyPayload-Werte

Berechtigung: process.send auf Ziel-PID

-- Einfaches Spawnen
local pid, err = process.spawn(id, host, ...)
-- Mit Überwachung (EXIT-Events empfangen)
local pid, err = process.spawn_monitored(id, host, ...)
-- Mit Linking (LINK_DOWN bei abnormalem Exit empfangen)
local pid, err = process.spawn_linked(id, host, ...)
-- Sowohl gelinkt als auch überwacht
local pid, err = process.spawn_linked_monitored(id, host, ...)
ParameterTypBeschreibung
idstringProzessquellen-ID (z.B. "app.workers:handler")
hoststringHost-ID (z.B. "app:processes")
...anyArgumente, die an den gespawnten Prozess übergeben werden

Berechtigungen:

  • process.spawn auf Prozess-ID
  • process.host auf Host-ID
  • process.spawn.monitored auf Prozess-ID (für überwachte Varianten)
  • process.spawn.linked auf Prozess-ID (für gelinkte Varianten)
-- Prozess zwangsweise beenden
local ok, err = process.terminate(destination)
-- Ordnungsgemäße Kanzellierung mit optionalem Grund anfordern
local ok, err = process.cancel(destination, "shutting down")
ParameterTypBeschreibung
destinationstringPID oder registrierter Name
reasonstringOptionaler Grund, der dem Ziel übermittelt wird

Berechtigungen: process.terminate, process.cancel auf Ziel-PID

Einen existierenden Prozess überwachen oder linken:

-- Überwachung: EXIT-Events empfangen, wenn Ziel beendet wird
local ok, err = process.monitor(destination)
local ok, err = process.unmonitor(destination)
-- Linking: bidirektional, LINK_DOWN bei abnormalem Exit empfangen
local ok, err = process.link(destination)
local ok, err = process.unlink(destination)

Berechtigungen: process.monitor, process.unmonitor, process.link, process.unlink auf Ziel-PID

local options = process.get_options()
local ok, err = process.set_options({trap_links = true})
FeldTypBeschreibung
trap_linksbooleanOb LINK_DOWN-Events an den Events-Channel geliefert werden

Channels zum Empfangen von Nachrichten und Lebenszyklusereignissen holen:

local inbox = process.inbox() -- Message-Objekte vom @inbox-Topic
local events = process.events() -- Lebenszyklusereignisse vom @events-Topic
KonstanteBeschreibung
process.event.CANCELKanzellierung angefordert
process.event.EXITÜberwachter Prozess beendet
process.event.LINK_DOWNGelinkter Prozess abnormal beendet
FeldTypBeschreibung
kindstringEvent-Typ-Konstante
fromstringQuell-PID
resultanyFür EXIT: der zurückgegebene Wert (bei normalem Exit vorhanden)
erroranyFür EXIT: der Fehler (bei abnormalem Exit vorhanden)
reasonstringFür CANCEL: Grund der Kanzellierung

Benutzerdefinierte Topics abonnieren:

local ch = process.listen(topic, options)
process.unlisten(ch)
ParameterTypBeschreibung
topicstringTopic-Name (darf nicht mit @ beginnen)
options.messagebooleanWenn true, Message-Objekte empfangen; wenn false, rohe Payloads

Beim Empfangen von inbox oder mit {message = true}:

local msg = inbox:receive()
msg:topic() -- string: Topic-Name
msg:from() -- string|nil: Absender-PID
msg:payload() -- Payload: Wrapper (`:data()` aufrufen zum Extrahieren)
msg:payload():data() -- any: tatsächlicher Payload-Wert

Einen Prozess spawnen, auf sein Ergebnis warten und zurückgeben:

local result, err = process.exec(id, host, ...)

Berechtigungen: process.exec auf Prozess-ID, process.host auf Host-ID

Den aktuellen Prozess auf eine neue Definition upgraden und dabei die PID beibehalten:

-- Auf neue Version upgraden, Zustand übergeben
process.upgrade(id, ...)
-- Gleiche Definition behalten, mit neuem Zustand erneut ausführen
process.upgrade(nil, preserved_state)

Einen Spawner mit benutzerdefiniertem Kontext für Kindprozesse erstellen:

local spawner = process.with_context({request_id = "123"})

Berechtigung: process.context auf “context”

process.with_options(options) erstellt einen Spawner, der spawn-zeitliche Optionen (z.B. einen Netzwerk-Selektor) anstelle von Kontextwerten trägt:

local spawner = process.with_options({network = "app:tor_proxy"})
OptionTypBeschreibung
networkstringRegistry-ID eines network.*-Eintrags für die ausgehenden Verbindungen des Kindprozesses

Berechtigung: process.context auf “context”; die Auswahl eines Netzwerks erfordert zusätzlich network.select auf dieser Netzwerk-ID.

SpawnBuilder ist unveränderlich - jede Methode gibt eine neue Instanz zurück:

spawner:with_context(values) -- Kontextwerte hinzufügen
spawner:with_actor(actor) -- Sicherheits-Actor setzen
spawner:with_scope(scope) -- Sicherheits-Scope setzen
spawner:with_name(name) -- Prozessname setzen
spawner:with_message(topic, ...) -- Nachricht zum Senden nach Spawn einreihen
spawner:with_options(options) -- Spawn-Optionen zusammenführen (z. B. network)

Berechtigung: process.security auf “security” für :with_actor() und :with_scope()

spawner:spawn(id, host, ...)
spawner:spawn_monitored(id, host, ...)
spawner:spawn_linked(id, host, ...)
spawner:spawn_linked_monitored(id, host, ...)

Gleiche Berechtigungen wie Modul-Level-Spawn-Funktionen.

Einen Prozess unter einem Namen registrieren und über diesen Namen statt seiner PID erreichen. Jede Funktion, die ein destination akzeptiert (send, terminate, cancel, monitor, link, …), nimmt statt einer PID auch einen registrierten Namen.

local ok, err = process.registry.register(name) -- self, lokaler Scope
local pid, err = process.registry.lookup(name)
local ok, err = process.registry.unregister(name)

Das optionale scope-Argument wählt die Konsistenzgarantie des Namens. Standard ist LOCAL. Die vier Scopes und ihre Garantien sind im Cluster-Leitfaden beschrieben; kurz gefasst:

KonstanteSichtbarkeitGarantie
process.registry.LOCALnur dieser KnotenSofort, knotenlokal
process.registry.EVENTUALclusterweitEventual Consistent (Gossip)
process.registry.CONSISTENTclusterweitLinearisierbarer Singleton (Raft)
process.registry.STRONGclusterweitKonsistent + jeder lebende Knoten bestätigt

Auf einem Einzelknoten ist nur LOCAL bedeutsam; die Cluster-Scopes erfordern Clustering.

local ok, err = process.registry.register(name, pid, scope)
ParameterTypErforderlichStandardBeschreibung
namestringjaZu registrierender Name
pidstringneinselfZu registrierende PID; Standard ist der aufrufende Prozess
scopenumberneinLOCALEine der obigen Scope-Konstanten

Gibt true bei Erfolg zurück, oder nil, error bei Fehler. Konflikte (Name bereits für eine andere PID unter einem Cluster-Scope registriert) geben errors.ALREADY_EXISTS zurück. Das Registrieren desselben Namens für dieselbe PID ist idempotent. Eine STRONG-Registrierung blockiert, bis jeder lebende Knoten bestätigt oder die Reservierungsdeadline abläuft; bei Timeout wird ein Fehler zurückgegeben.

Das Registrieren im Namen einer anderen PID erfordert zusätzlich die Berechtigung process.registry.foreign auf der Ziel-PID.

local pid, err = process.registry.lookup(name)

Gibt den registrierten PID-String zurück, oder nil, error mit der Art errors.NOT_FOUND, wenn der Name nicht registriert ist.

local ok, err = process.registry.unregister(name, scope)

scope ist standardmäßig LOCAL und muss mit dem Scope übereinstimmen, unter dem der Name registriert wurde. Für CONSISTENT und STRONG ist der besitzende Prozess derjenige, dem die Deregistrierung erlaubt ist; das Deregistrieren eines von einer anderen PID gehaltenen Namens gibt false zurück. Namen werden auch automatisch freigegeben, wenn der besitzende Prozess endet (und für Cluster-Scopes, wenn sein Knoten ausscheidet), sodass explizites Deregistrieren für vorzeitige Freigabe ist.

Berechtigungen steuern, was ein aufrufender Prozess tun kann. Alle Prüfungen verwenden den Sicherheitskontext des Aufrufers (Actor) gegen die Zielressource.

Richtlinien können basierend auf Folgendem erlauben/ablehnen:

  • Actor: Der Sicherheitsprinzipal, der die Anfrage stellt
  • Aktion: Die durchgeführte Operation (z.B. process.send)
  • Ressource: Das Ziel (PID, Prozess-ID, Host-ID oder Name)
  • Attribute: Zusätzlicher Kontext einschließlich pid (Prozess-ID des Aufrufers)
BerechtigungFunktionenRessource
process.spawnspawn*()Prozess-ID
process.spawn.monitoredspawn_monitored(), spawn_linked_monitored()Prozess-ID
process.spawn.linkedspawn_linked(), spawn_linked_monitored()Prozess-ID
process.hostspawn*(), exec()Host-ID
process.sendsend()Ziel-PID
process.execexec()Prozess-ID
process.terminateterminate()Ziel-PID
process.cancelcancel()Ziel-PID
process.monitormonitor()Ziel-PID
process.unmonitorunmonitor()Ziel-PID
process.linklink()Ziel-PID
process.unlinkunlink()Ziel-PID
process.contextwith_context()”context”
process.security:with_actor(), :with_scope()”security”
process.registry.registerregistry.register()Name
process.registry.unregisterregistry.unregister()Name
process.registry.foreignregistry.register()Ziel-PID

Cluster-Namens-Scopes werden durch scope-suffixierte Varianten dieser Aktionen autorisiert (process.registry.register.eventual, .consistent, .strong und die entsprechenden unregister-Aktionen), sodass eine Richtlinie lokale Benennung separat von clusterweiter Benennung gewähren kann.

Einige Operationen erfordern mehrere Berechtigungen:

OperationErforderliche Berechtigungen
spawn()process.spawn + process.host
spawn_monitored()process.spawn + process.spawn.monitored + process.host
spawn_linked()process.spawn + process.spawn.linked + process.host
spawn_linked_monitored()process.spawn + process.spawn.monitored + process.spawn.linked + process.host
exec()process.exec + process.host
Spawn mit benutzerdefiniertem Actor/ScopeSpawn-Berechtigungen + process.security
BedingungArt
Kein Kontext gefundenerrors.INVALID
Frame-Kontext nicht gefundenerrors.INVALID
Fehlende erforderliche Argumenteerrors.INVALID
Reserviertes Topic-Präfix (@)errors.INVALID
Ungültiges Dauerformaterrors.INVALID
Name nicht registrierterrors.NOT_FOUND
Berechtigung verweigerterrors.PERMISSION_DENIED
Name bereits registrierterrors.ALREADY_EXISTS

Siehe Fehlerbehandlung für die Arbeit mit Fehlern.