update actor doc and add more actor based tests

This commit is contained in:
2026-02-17 11:50:46 -06:00
parent 2d054fcf21
commit 2be2b15a61
21 changed files with 268 additions and 51 deletions

View File

@@ -67,9 +67,9 @@ An actor is a script that **does not return a value**. It runs as an independent
// worker.ce
print("Worker started")
$receiver(function(msg, reply) {
$receiver(function(msg) {
print("Received:", msg)
// Process message...
send(msg, {status: "ok"})
})
```
@@ -83,106 +83,128 @@ $receiver(function(msg, reply) {
Actors have access to special functions prefixed with `$`:
### $me
### $self
Reference to the current actor.
Reference to the current actor. This is a stone (immutable) actor object.
```javascript
print($me) // actor reference
print($self) // actor reference
print(is_actor($self)) // true
```
### $overling
Reference to the parent actor that started this actor. `null` for the root actor. Child actors are automatically coupled to their overling — if the parent dies, the child dies too.
```javascript
if ($overling != null) {
send($overling, {status: "ready"})
}
```
### $stop()
Stop the current actor.
Stop the current actor. When called with an actor argument, stops that underling (child) instead.
```javascript
$stop()
$stop() // stop self
$stop(child) // stop a child actor
```
### $send(actor, message, callback)
Send a message to another actor.
```javascript
$send(other_actor, {type: "ping", data: 42}, function(reply) {
print("Got reply:", reply)
})
```
Messages are automatically **splatted** — flattened to plain data without prototypes.
### $start(callback, program)
Start a new actor from a script.
Start a new child actor from a script. The callback receives lifecycle events:
- `{type: "greet", actor: <ref>}` — child started successfully
- `{type: "stop"}` — child stopped cleanly
- `{type: "disrupt", reason: ...}` — child crashed
```javascript
$start(function(new_actor) {
print("Started:", new_actor)
$start(function(event) {
if (event.type == 'greet') {
print("Child started:", event.actor)
send(event.actor, {task: "work"})
}
if (event.type == 'stop') {
print("Child stopped")
}
if (event.type == 'disrupt') {
print("Child crashed:", event.reason)
}
}, "worker")
```
### $delay(callback, seconds)
Schedule a callback after a delay.
Schedule a callback after a delay. Returns a cancel function that can be called to prevent the callback from firing.
```javascript
$delay(function() {
var cancel = $delay(function() {
print("5 seconds later")
}, 5)
// To cancel before it fires:
cancel()
```
### $clock(callback)
Get called every frame/tick.
Get called every frame/tick. The callback receives the current time as a number.
```javascript
$clock(function(dt) {
// Called each tick with delta time
$clock(function(t) {
// called each tick with current time
})
```
### $receiver(callback)
Set up a message receiver.
Set up a message receiver. The callback is called with the incoming message whenever another actor sends a message to this actor.
To reply to a message, call `send(message, reply_data)` — the message object contains routing information that directs the reply back to the sender.
```javascript
$receiver(function(message, reply) {
// Handle incoming message
reply({status: "ok"})
$receiver(function(message) {
// handle incoming message
send(message, {status: "ok"})
})
```
### $portal(callback, port)
Open a network port.
Open a network port to receive connections from remote actors.
```javascript
$portal(function(connection) {
// Handle new connection
// handle new connection
}, 8080)
```
### $contact(callback, record)
Connect to a remote address.
Connect to a remote actor at a given address.
```javascript
$contact(function(connection) {
// Connected
// connected
}, {host: "example.com", port: 80})
```
### $time_limit(requestor, seconds)
Wrap a requestor with a timeout. See [Requestors](/docs/requestors/) for details.
Wrap a requestor with a timeout. Returns a new requestor that will cancel the original and call its callback with a failure if the time limit is exceeded. See [Requestors](/docs/requestors/) for details.
```javascript
$time_limit(my_requestor, 10) // 10 second timeout
var timed = $time_limit(my_requestor, 10)
timed(function(result, reason) {
// reason will explain timeout if it fires
}, initial_value)
```
### $couple(actor)
Couple the current actor to another actor. When the coupled actor dies, the current actor also dies. Coupling is automatic between an actor and its overling (parent).
Couple the current actor to another actor. When the coupled actor dies, the current actor also dies. Coupling is automatic between a child actor and its overling (parent).
```javascript
$couple(other_actor)
@@ -190,7 +212,7 @@ $couple(other_actor)
### $unneeded(callback, seconds)
Schedule the actor for removal after a specified time.
Schedule the actor for removal after a specified time. The callback fires when the time elapses.
```javascript
$unneeded(function() {
@@ -200,20 +222,76 @@ $unneeded(function() {
### $connection(callback, actor, config)
Get information about the connection to another actor, such as latency, bandwidth, and activity.
Get information about the connection to another actor. For local actors, returns `{type: "local"}`. For remote actors, returns connection details including latency, bandwidth, and activity.
```javascript
$connection(function(info) {
print(info.latency)
if (info.type == "local") {
print("same machine")
} else {
print(info.latency)
}
}, other_actor, {})
```
## Runtime Functions
These functions are available in actors without the `$` prefix:
### send(actor, message, callback)
Send a message to another actor. The message must be an object record.
The optional callback receives the reply when the recipient responds.
```javascript
send(other_actor, {type: "ping"}, function(reply) {
print("Got reply:", reply)
})
```
To reply to a received message, pass the message itself as the first argument — it contains routing information:
```javascript
$receiver(function(message) {
send(message, {result: 42})
})
```
Messages are automatically flattened to plain data.
### is_actor(value)
Returns `true` if the value is an actor reference.
```javascript
if (is_actor(some_value)) {
send(some_value, {ping: true})
}
```
### log
Logging functions: `log.console(msg)`, `log.error(msg)`, `log.system(msg)`.
### use(path)
Import a module. See [Module Resolution](#module-resolution) below.
### args
Array of command-line arguments passed to the actor.
### sequence(), parallel(), race(), fallback()
Requestor composition functions. See [Requestors](/docs/requestors/) for details.
## Module Resolution
When you call `use('name')`, ƿit searches:
1. **Current package** — files relative to package root
2. **Dependencies** — packages declared in `pit.toml`
2. **Dependencies** — packages declared in `cell.toml`
3. **Core** — built-in ƿit modules
```javascript
@@ -234,8 +312,14 @@ var config = use('config')
print("Starting application...")
$start(function(worker) {
$send(worker, {task: "process", data: [1, 2, 3]})
$start(function(event) {
if (event.type == 'greet') {
send(event.actor, {task: "process", data: [1, 2, 3]})
}
if (event.type == 'stop') {
print("Worker finished")
$stop()
}
}, "worker")
$delay(function() {
@@ -246,11 +330,12 @@ $delay(function() {
```javascript
// worker.ce - Worker actor
$receiver(function(msg, reply) {
$receiver(function(msg) {
if (msg.task == "process") {
var result = array(msg.data, x => x * 2)
reply({result: result})
var result = array(msg.data, function(x) { return x * 2 })
send(msg, {result: result})
}
$stop()
})
```

View File

@@ -31,7 +31,7 @@ The cancel function, when called, should abort the in-progress work.
```javascript
var fetch_data = function(callback, url) {
$contact(function(connection) {
$send(connection, {get: url}, function(response) {
send(connection, {get: url}, function(response) {
callback(response)
})
}, {host: url, port: 80})
@@ -154,11 +154,11 @@ If the requestor does not complete within the time limit, it is cancelled and th
## Requestors and Actors
Requestors are particularly useful with actor messaging. Since `$send` is callback-based, it fits naturally:
Requestors are particularly useful with actor messaging. Since `send` is callback-based, it fits naturally:
```javascript
var ask_worker = function(callback, task) {
$send(worker, task, function(reply) {
send(worker, task, function(reply) {
callback(reply)
})
}