Process Management
Process Management
Section titled “Process Management”Spawn, monitor, and communicate with child processes. Implements actor-model patterns with message passing, supervision, and lifecycle management.
The process global is always available — it does not require require() and does not need to be listed in modules:.
Process Information
Section titled “Process Information”Get the current frame ID or process ID:
local frame_id = process.id() -- Call chain identifierlocal pid = process.pid() -- Process IDSending Messages
Section titled “Sending Messages”Send message(s) to a process by PID or registered name:
local ok, err = process.send(destination, topic, ...)| Parameter | Type | Description |
|---|---|---|
destination | string | PID or registered name |
topic | string | Topic name (cannot start with @) |
... | any | Payload values |
Permission: process.send on target PID
Spawning Processes
Section titled “Spawning Processes”-- Basic spawnlocal pid, err = process.spawn(id, host, ...)
-- With monitoring (receive EXIT events)local pid, err = process.spawn_monitored(id, host, ...)
-- With linking (receive LINK_DOWN on abnormal exit)local pid, err = process.spawn_linked(id, host, ...)
-- Both linked and monitoredlocal pid, err = process.spawn_linked_monitored(id, host, ...)| Parameter | Type | Description |
|---|---|---|
id | string | Process source ID (e.g., "app.workers:handler") |
host | string | Host ID (e.g., "app:processes") |
... | any | Arguments passed to spawned process |
Permissions:
process.spawnon process idprocess.hoston host idprocess.spawn.monitoredon process id (for monitored variants)process.spawn.linkedon process id (for linked variants)
Process Control
Section titled “Process Control”-- Forcefully terminate a processlocal ok, err = process.terminate(destination)
-- Request graceful cancellation with an optional reasonlocal ok, err = process.cancel(destination, "shutting down")| Parameter | Type | Description |
|---|---|---|
destination | string | PID or registered name |
reason | string | Optional reason delivered to the target |
Permissions: process.terminate, process.cancel on target PID
Monitoring and Linking
Section titled “Monitoring and Linking”Monitor or link to an existing process:
-- Monitoring: receive EXIT events when target exitslocal ok, err = process.monitor(destination)local ok, err = process.unmonitor(destination)
-- Linking: bidirectional, receive LINK_DOWN on abnormal exitlocal ok, err = process.link(destination)local ok, err = process.unlink(destination)Permissions: process.monitor, process.unmonitor, process.link, process.unlink on target PID
Process Options
Section titled “Process Options”local options = process.get_options()local ok, err = process.set_options({trap_links = true})| Field | Type | Description |
|---|---|---|
trap_links | boolean | Whether LINK_DOWN events are delivered to events channel |
Inbox and Events
Section titled “Inbox and Events”Get channels for receiving messages and lifecycle events:
local inbox = process.inbox() -- Message objects from @inbox topiclocal events = process.events() -- Lifecycle events from @events topicEvent Types
Section titled “Event Types”| Constant | Description |
|---|---|
process.event.CANCEL | Cancellation requested |
process.event.EXIT | Monitored process exited |
process.event.LINK_DOWN | Linked process terminated abnormally |
Event Fields
Section titled “Event Fields”| Field | Type | Description |
|---|---|---|
kind | string | Event type constant |
from | string | Source PID |
result | table | For EXIT/LINK_DOWN: a {value, error} record; the process return value is at result.value and any error at result.error |
reason | string | For CANCEL: why the process is being cancelled |
Topic Subscription
Section titled “Topic Subscription”Subscribe to custom topics:
local ch = process.listen(topic, options)process.unlisten(ch)| Parameter | Type | Description |
|---|---|---|
topic | string | Topic name (cannot start with @) |
options.message | boolean | If true, receive Message objects; if false, raw payloads |
Message Objects
Section titled “Message Objects”When receiving from inbox or with {message = true}:
local msg = inbox:receive()
msg:topic() -- string: topic namemsg:from() -- string|nil: sender PIDmsg:payload() -- Payload: wrapper (call :data() to extract)msg:payload():data() -- any: actual payload valueSynchronous Call
Section titled “Synchronous Call”Spawn a process, wait for its result, and return:
local result, err = process.exec(id, host, ...)Permissions: process.exec on process id, process.host on host id
Process Upgrade
Section titled “Process Upgrade”Upgrade the current process to a new definition while preserving PID:
-- Upgrade to new version, passing stateprocess.upgrade(id, ...)
-- Keep same definition, re-run with new stateprocess.upgrade(nil, preserved_state)Context Spawner
Section titled “Context Spawner”Create a spawner with custom context for child processes:
local spawner = process.with_context({request_id = "123"})Permission: process.context on “context”
Spawner with Options
Section titled “Spawner with Options”process.with_options(options) creates a spawner that carries spawn-time options (e.g., a network selector) instead of context values:
local spawner = process.with_options({network = "app:tor_proxy"})| Option | Type | Description |
|---|---|---|
network | string | Registry ID of a network.* entry to use for the child’s outbound connections |
Permission: process.context on “context”; selecting a network additionally requires network.select on that network ID.
SpawnBuilder Methods
Section titled “SpawnBuilder Methods”SpawnBuilder is immutable - each method returns a new instance:
spawner:with_context(values) -- Add context valuesspawner:with_actor(actor) -- Set security actorspawner:with_scope(scope) -- Set security scopespawner:with_name(name) -- Set process namespawner:with_message(topic, ...) -- Queue message to send after spawnspawner:with_options(options) -- Merge spawn-time options (e.g. network)Permission: process.security on “security” for :with_actor() and :with_scope()
Spawner Spawn Methods
Section titled “Spawner Spawn Methods”spawner:spawn(id, host, ...)spawner:spawn_monitored(id, host, ...)spawner:spawn_linked(id, host, ...)spawner:spawn_linked_monitored(id, host, ...)Same permissions as module-level spawn functions.
Name Registry
Section titled “Name Registry”Register a process under a name and reach it by that name instead of its PID. Any function that takes a destination (send, terminate, cancel, monitor, link, …) accepts a registered name in place of a PID.
local ok, err = process.registry.register(name) -- self, local scopelocal pid, err = process.registry.lookup(name)local ok, err = process.registry.unregister(name)The optional scope argument selects the consistency guarantee of the name. It defaults to LOCAL. The four scopes and their guarantees are described in the Cluster Guide; in short:
| Constant | Visibility | Guarantee |
|---|---|---|
process.registry.LOCAL | this node only | Instant, node-local |
process.registry.EVENTUAL | cluster-wide | Eventually consistent (gossip) |
process.registry.CONSISTENT | cluster-wide | Linearizable singleton (Raft) |
process.registry.STRONG | cluster-wide | Consistent + every live node acknowledges |
On a standalone node only LOCAL is meaningful; the cluster scopes require clustering.
register
Section titled “register”local ok, err = process.registry.register(name, pid, scope)| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | yes | Name to register | |
pid | string | no | self | PID to register; defaults to the calling process |
scope | number | no | LOCAL | One of the scope constants above |
Returns true on success, or nil, error on failure. Conflicts (name already registered to a different PID under a cluster scope) return errors.ALREADY_EXISTS. Registering the same name to the same PID is idempotent. A STRONG registration blocks until every live node acknowledges or the reservation deadline expires; on timeout it returns an error.
Registering on behalf of a different PID additionally requires the process.registry.foreign permission on the target PID.
lookup
Section titled “lookup”local pid, err = process.registry.lookup(name)Returns the registered PID string, or nil, error with kind errors.NOT_FOUND when the name is not registered.
unregister
Section titled “unregister”local ok, err = process.registry.unregister(name, scope)scope defaults to LOCAL and must match the scope the name was registered under. For CONSISTENT and STRONG, the owning process is the one allowed to unregister; unregistering a name owned by another PID returns false. Names also release automatically when the owning process exits (and, for cluster scopes, when its node leaves), so explicit unregister is for early release.
Permissions
Section titled “Permissions”Permissions control what a calling process can do. All checks use the caller’s security context (actor) against the target resource.
Policy Evaluation
Section titled “Policy Evaluation”Policies can allow/deny based on:
- Actor: The security principal making the request
- Action: The operation being performed (e.g.,
process.send) - Resource: The target (PID, process id, host id, or name)
- Attributes: Additional context including
pid(caller’s process ID)
Permission Reference
Section titled “Permission Reference”| Permission | Functions | Resource |
|---|---|---|
process.spawn | spawn*() | process id |
process.spawn.monitored | spawn_monitored(), spawn_linked_monitored() | process id |
process.spawn.linked | spawn_linked(), spawn_linked_monitored() | process id |
process.host | spawn*(), exec() | host id |
process.send | send() | target PID |
process.exec | exec() | process id |
process.terminate | terminate() | target PID |
process.cancel | cancel() | target PID |
process.monitor | monitor() | target PID |
process.unmonitor | unmonitor() | target PID |
process.link | link() | target PID |
process.unlink | unlink() | target PID |
process.context | with_context() | ”context” |
process.security | :with_actor(), :with_scope() | ”security” |
process.registry.register | registry.register() | name |
process.registry.unregister | registry.unregister() | name |
process.registry.foreign | registry.register() | target PID |
Cluster name scopes are authorized by scope-suffixed variants of these actions (process.registry.register.eventual, .consistent, .strong, and the matching unregister actions), so a policy can grant local naming separately from cluster-wide naming.
Multiple Permissions
Section titled “Multiple Permissions”Some operations require multiple permissions:
| Operation | Required Permissions |
|---|---|
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 with custom actor/scope | spawn permissions + process.security |
Errors
Section titled “Errors”| Condition | Kind |
|---|---|
| No context found | errors.INVALID |
| Frame context not found | errors.INVALID |
| Missing required arguments | errors.INVALID |
Reserved topic prefix (@) | errors.INVALID |
| Invalid duration format | errors.INVALID |
| Name not registered | errors.NOT_FOUND |
| Permission denied | errors.PERMISSION_DENIED |
| Name already registered | errors.ALREADY_EXISTS |
See Error Handling for working with errors.
See Also
Section titled “See Also”- Channels - Inter-process communication
- Message Queue - Queue-based messaging
- Functions - Function invocation
- Supervision - Process lifecycle management
- Cluster - Name scopes and cluster-wide naming