Merge branch 'fix_actors'
This commit is contained in:
179
docs/actors.md
179
docs/actors.md
@@ -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()
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user