mirror of
https://github.com/actix/actix-website
synced 2024-11-27 10:02:57 +01:00
prettier markdown
This commit is contained in:
parent
7c4b52623e
commit
0d0e7f4433
@ -1,6 +1,6 @@
|
|||||||
singleQuote: true
|
|
||||||
tabWidth: 2
|
tabWidth: 2
|
||||||
overrides:
|
overrides:
|
||||||
- files: ["*.md"]
|
- files: ['*.md']
|
||||||
options:
|
options:
|
||||||
proseWrap: never
|
proseWrap: never
|
||||||
|
printWidth: 9999
|
||||||
|
@ -5,8 +5,7 @@ slug: /actix
|
|||||||
|
|
||||||
# Quick start
|
# Quick start
|
||||||
|
|
||||||
Before you can start writing an actix application, you’ll need a version of Rust installed.
|
Before you can start writing an actix application, you’ll need a version of Rust installed. We recommend you use rustup to install or configure such a version.
|
||||||
We recommend you use rustup to install or configure such a version.
|
|
||||||
|
|
||||||
## Install Rust
|
## Install Rust
|
||||||
|
|
||||||
@ -26,9 +25,7 @@ The actix framework requires Rust version 1.40.0 and up.
|
|||||||
|
|
||||||
## Running Examples
|
## Running Examples
|
||||||
|
|
||||||
The fastest way to start experimenting with actix is to clone the actix repository
|
The fastest way to start experimenting with actix is to clone the actix repository and run the included examples in the examples/ directory. The following set of commands runs the `ping` example:
|
||||||
and run the included examples in the examples/ directory. The following set of
|
|
||||||
commands runs the `ping` example:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/actix/actix
|
git clone https://github.com/actix/actix
|
||||||
|
@ -5,23 +5,20 @@ slug: /actix/getting-started
|
|||||||
|
|
||||||
# Getting Started
|
# Getting Started
|
||||||
|
|
||||||
Let’s create and run our first actix application. We’ll create a new Cargo project
|
Let’s create and run our first actix application. We’ll create a new Cargo project that depends on actix and then run the application.
|
||||||
that depends on actix and then run the application.
|
|
||||||
|
|
||||||
In previous section we already installed required rust version. Now let's create new cargo projects.
|
In previous section we already installed required rust version. Now let's create new cargo projects.
|
||||||
|
|
||||||
## Ping actor
|
## Ping actor
|
||||||
|
|
||||||
Let’s write our first actix application! Start by creating a new binary-based
|
Let’s write our first actix application! Start by creating a new binary-based Cargo project and changing into the new directory:
|
||||||
Cargo project and changing into the new directory:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo new actor-ping
|
cargo new actor-ping
|
||||||
cd actor-ping
|
cd actor-ping
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, add actix as a dependency of your project by ensuring your Cargo.toml
|
Now, add actix as a dependency of your project by ensuring your Cargo.toml contains the following:
|
||||||
contains the following:
|
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@ -45,11 +42,9 @@ impl Actor for MyActor {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Each actor has an execution context, for `MyActor` we are going to use `Context<A>`. More information
|
Each actor has an execution context, for `MyActor` we are going to use `Context<A>`. More information on actor contexts is available in the next section.
|
||||||
on actor contexts is available in the next section.
|
|
||||||
|
|
||||||
Now we need to define the `Message` that the actor needs to accept. The message can be any type
|
Now we need to define the `Message` that the actor needs to accept. The message can be any type that implements the `Message` trait.
|
||||||
that implements the `Message` trait.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
@ -59,12 +54,9 @@ use actix::prelude::*;
|
|||||||
struct Ping(usize);
|
struct Ping(usize);
|
||||||
```
|
```
|
||||||
|
|
||||||
The main purpose of the `Message` trait is to define a result type. The `Ping` message defines
|
The main purpose of the `Message` trait is to define a result type. The `Ping` message defines `usize`, which indicates that any actor that can accept a `Ping` message needs to return `usize` value.
|
||||||
`usize`, which indicates that any actor that can accept a `Ping` message needs to
|
|
||||||
return `usize` value.
|
|
||||||
|
|
||||||
And finally, we need to declare that our actor `MyActor` can accept `Ping` and handle it.
|
And finally, we need to declare that our actor `MyActor` can accept `Ping` and handle it. To do this, the actor needs to implement the `Handler<Ping>` trait.
|
||||||
To do this, the actor needs to implement the `Handler<Ping>` trait.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
impl Handler<Ping> for MyActor {
|
impl Handler<Ping> for MyActor {
|
||||||
@ -78,21 +70,13 @@ impl Handler<Ping> for MyActor {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
That's it. Now we just need to start our actor and send a message to it.
|
That's it. Now we just need to start our actor and send a message to it. The start procedure depends on the actor's context implementation. In our case we can use `Context<A>` which is tokio/future based. We can start it with `Actor::start()` or `Actor::create()`. The first is used when the actor instance can be created immediately. The second method is used in case we need access to the context object before we can create the actor instance. In case of the `MyActor` actor we can use `start()`.
|
||||||
The start procedure depends on the actor's context implementation. In our case we can use
|
|
||||||
`Context<A>` which is tokio/future based. We can start it with `Actor::start()`
|
|
||||||
or `Actor::create()`. The first is used when the actor instance can be created immediately.
|
|
||||||
The second method is used in case we need access to the context object before we can create
|
|
||||||
the actor instance. In case of the `MyActor` actor we can use `start()`.
|
|
||||||
|
|
||||||
All communication with actors goes through an address. You can `do_send` a message
|
All communication with actors goes through an address. You can `do_send` a message without waiting for a response, or `send` to an actor with a specific message. Both `start()` and `create()` return an address object.
|
||||||
without waiting for a response, or `send` to an actor with a specific message.
|
|
||||||
Both `start()` and `create()` return an address object.
|
|
||||||
|
|
||||||
In the following example we are going to create a `MyActor` actor and send one message.
|
In the following example we are going to create a `MyActor` actor and send one message.
|
||||||
|
|
||||||
Here we use the actix-rt as way to start our System and drive our main Future
|
Here we use the actix-rt as way to start our System and drive our main Future so we can easily `.await` for the messages sent to the Actor.
|
||||||
so we can easily `.await` for the messages sent to the Actor.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[actix_rt::main]
|
#[actix_rt::main]
|
||||||
|
@ -7,26 +7,15 @@ slug: /actix/actor
|
|||||||
|
|
||||||
Actix is a rust library providing a framework for developing concurrent applications.
|
Actix is a rust library providing a framework for developing concurrent applications.
|
||||||
|
|
||||||
Actix is built on the [Actor Model] which
|
Actix is built on the [Actor Model] which allows applications to be written as a group of independently executing but cooperating "Actors" which communicate via messages. Actors are objects which encapsulate state and behavior and run within the _Actor System_ provided by the actix library.
|
||||||
allows applications to be written as a group of independently executing but cooperating
|
|
||||||
"Actors" which communicate via messages. Actors are objects which encapsulate
|
|
||||||
state and behavior and run within the *Actor System* provided by the actix library.
|
|
||||||
|
|
||||||
Actors run within a specific execution context [`Context<A>`].
|
Actors run within a specific execution context [`Context<A>`]. The context object is available only during execution. Each actor has a separate execution context. The execution context also controls the lifecycle of an actor.
|
||||||
The context object is available only during execution. Each actor has a separate
|
|
||||||
execution context. The execution context also controls the lifecycle of an actor.
|
|
||||||
|
|
||||||
Actors communicate exclusively by exchanging messages. The sending actor can
|
Actors communicate exclusively by exchanging messages. The sending actor can optionally wait for the response. Actors are not referenced directly, but by means of addresses.
|
||||||
optionally wait for the response. Actors are not referenced directly, but by means
|
|
||||||
of addresses.
|
|
||||||
|
|
||||||
Any rust type can be an actor, it only needs to implement the [`Actor`] trait.
|
Any rust type can be an actor, it only needs to implement the [`Actor`] trait.
|
||||||
|
|
||||||
To be able to handle a specific message the actor has to provide a
|
To be able to handle a specific message the actor has to provide a [`Handler<M>`] implementation for this message. All messages are statically typed. The message can be handled in an asynchronous fashion. Actor can spawn other actors or add futures or streams to execution context. The `Actor` trait provides several methods that allow controlling the actor's lifecycle.
|
||||||
[`Handler<M>`] implementation for this message. All messages
|
|
||||||
are statically typed. The message can be handled in an asynchronous fashion.
|
|
||||||
Actor can spawn other actors or add futures or streams to execution context.
|
|
||||||
The `Actor` trait provides several methods that allow controlling the actor's lifecycle.
|
|
||||||
|
|
||||||
[Actor Model]: https://en.wikipedia.org/wiki/Actor_model
|
[Actor Model]: https://en.wikipedia.org/wiki/Actor_model
|
||||||
[`Context<A>`]: ./context
|
[`Context<A>`]: ./context
|
||||||
@ -37,46 +26,33 @@ The `Actor` trait provides several methods that allow controlling the actor's li
|
|||||||
|
|
||||||
### Started
|
### Started
|
||||||
|
|
||||||
An actor always starts in the `Started` state. During this state the actor's `started()`
|
An actor always starts in the `Started` state. During this state the actor's `started()` method is called. The `Actor` trait provides a default implementation for this method. The actor context is available during this state and the actor can start more actors or register async streams or do any other required configuration.
|
||||||
method is called. The `Actor` trait provides a default implementation for this method.
|
|
||||||
The actor context is available during this state and the actor can start more actors or register
|
|
||||||
async streams or do any other required configuration.
|
|
||||||
|
|
||||||
### Running
|
### Running
|
||||||
|
|
||||||
After an Actor's `started()` method is called, the actor transitions to the `Running` state.
|
After an Actor's `started()` method is called, the actor transitions to the `Running` state. The Actor can stay in `running` state indefinitely.
|
||||||
The Actor can stay in `running` state indefinitely.
|
|
||||||
|
|
||||||
### Stopping
|
### Stopping
|
||||||
|
|
||||||
The Actor's execution state changes to the `stopping` state in the following situations:
|
The Actor's execution state changes to the `stopping` state in the following situations:
|
||||||
|
|
||||||
* `Context::stop` is called by the actor itself
|
- `Context::stop` is called by the actor itself
|
||||||
* all addresses to the actor get dropped. i.e. no other actor references it.
|
- all addresses to the actor get dropped. i.e. no other actor references it.
|
||||||
* no event objects are registered in the context.
|
- no event objects are registered in the context.
|
||||||
|
|
||||||
An actor can restore from the `stopping` state to the `running` state by creating a new
|
An actor can restore from the `stopping` state to the `running` state by creating a new address or adding an event object, and by returning `Running::Continue`.
|
||||||
address or adding an event object, and by returning `Running::Continue`.
|
|
||||||
|
|
||||||
If an actor changed state to `stopping` because `Context::stop()` is called
|
If an actor changed state to `stopping` because `Context::stop()` is called then the context immediately stops processing incoming messages and calls `Actor::stopping()`. If the actor does not restore back to the `running` state, all unprocessed messages are dropped.
|
||||||
then the context immediately stops processing incoming messages and calls
|
|
||||||
`Actor::stopping()`. If the actor does not restore back to the `running` state, all
|
|
||||||
unprocessed messages are dropped.
|
|
||||||
|
|
||||||
By default this method returns `Running::Stop` which confirms the stop operation.
|
By default this method returns `Running::Stop` which confirms the stop operation.
|
||||||
|
|
||||||
### Stopped
|
### Stopped
|
||||||
|
|
||||||
If the actor does not modify the execution context during the stopping state, the actor state changes
|
If the actor does not modify the execution context during the stopping state, the actor state changes to `Stopped`. This state is considered final and at this point the actor is dropped.
|
||||||
to `Stopped`. This state is considered final and at this point the actor is dropped.
|
|
||||||
|
|
||||||
## Message
|
## Message
|
||||||
|
|
||||||
An Actor communicates with other actors by sending messages. In actix all
|
An Actor communicates with other actors by sending messages. In actix all messages are typed. A message can be any rust type which implements the [`Message`] trait. `Message::Result` defines the return type. Let's define a simple `Ping` message - an actor which will accept this message needs to return `Result<bool, std::io::Error>`.
|
||||||
messages are typed. A message can be any rust type which implements the
|
|
||||||
[`Message`] trait. `Message::Result` defines the return type.
|
|
||||||
Let's define a simple `Ping` message - an actor which will accept this message needs to return
|
|
||||||
`Result<bool, std::io::Error>`.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
@ -92,10 +68,7 @@ impl Message for Ping {
|
|||||||
|
|
||||||
## Spawning an actor
|
## Spawning an actor
|
||||||
|
|
||||||
How to start an actor depends on its context. Spawning a new async actor
|
How to start an actor depends on its context. Spawning a new async actor is achieved via the `start` and `create` methods of the [`Actor`] trait. It provides several different ways of creating actors; for details check the docs.
|
||||||
is achieved via the `start` and `create` methods of
|
|
||||||
the [`Actor`] trait. It provides several different ways of
|
|
||||||
creating actors; for details check the docs.
|
|
||||||
|
|
||||||
## Complete example
|
## Complete example
|
||||||
|
|
||||||
@ -152,10 +125,7 @@ async fn main() {
|
|||||||
|
|
||||||
## Responding with a MessageResponse
|
## Responding with a MessageResponse
|
||||||
|
|
||||||
Let's take a look at the `Result` type defined for the `impl Handler` in the above example.
|
Let's take a look at the `Result` type defined for the `impl Handler` in the above example. See how we're returning a `Result<bool, std::io::Error>`? We're able to respond to our actor's incoming message with this type because it has the `MessageResponse` trait implemented for that type. Here's the definition for that trait:
|
||||||
See how we're returning a `Result<bool, std::io::Error>`? We're able to respond to our actor's
|
|
||||||
incoming message with this type because it has the `MessageResponse` trait implemented for that type.
|
|
||||||
Here's the definition for that trait:
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
pub trait MessageResponse<A: Actor, M: Message> {
|
pub trait MessageResponse<A: Actor, M: Message> {
|
||||||
@ -163,10 +133,7 @@ pub trait MessageResponse<A: Actor, M: Message> {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Sometimes it makes sense to respond to incoming messages with types that don't have this trait
|
Sometimes it makes sense to respond to incoming messages with types that don't have this trait implemented for them. When that happens we can implement the trait ourselves. Here's an example where we're responding to a `Ping` message with a `GotPing`, and responding with `GotPong` for a `Pong` message.
|
||||||
implemented for them. When that happens we can implement the trait ourselves.
|
|
||||||
Here's an example where we're responding to a `Ping` message with a `GotPing`,
|
|
||||||
and responding with `GotPong` for a `Pong` message.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use actix::dev::{MessageResponse, OneshotSender};
|
use actix::dev::{MessageResponse, OneshotSender};
|
||||||
|
@ -5,15 +5,11 @@ slug: /actix/address
|
|||||||
|
|
||||||
# Address
|
# Address
|
||||||
|
|
||||||
Actors communicate exclusively by exchanging messages. The sending actor can optionally
|
Actors communicate exclusively by exchanging messages. The sending actor can optionally wait for the response. Actors cannot be referenced directly, only by their addresses.
|
||||||
wait for the response. Actors cannot be referenced directly, only by their addresses.
|
|
||||||
|
|
||||||
There are several ways to get the address of an actor. The `Actor` trait provides
|
There are several ways to get the address of an actor. The `Actor` trait provides two helper methods for starting an actor. Both return the address of the started actor.
|
||||||
two helper methods for starting an actor. Both return the address of the started actor.
|
|
||||||
|
|
||||||
Here is an example of `Actor::start()` method usage. In this example `MyActor` actor
|
Here is an example of `Actor::start()` method usage. In this example `MyActor` actor is asynchronous and is started in the same thread as the caller - threads are covered in the [SyncArbiter] chapter.
|
||||||
is asynchronous and is started in the same thread as the caller - threads are covered in
|
|
||||||
the [SyncArbiter] chapter.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
struct MyActor;
|
struct MyActor;
|
||||||
@ -24,8 +20,7 @@ impl Actor for MyActor {
|
|||||||
let addr = MyActor.start();
|
let addr = MyActor.start();
|
||||||
```
|
```
|
||||||
|
|
||||||
An async actor can get its address from the `Context` struct. The context needs to
|
An async actor can get its address from the `Context` struct. The context needs to implement the `AsyncContext` trait. `AsyncContext::address()` provides the actor's address.
|
||||||
implement the `AsyncContext` trait. `AsyncContext::address()` provides the actor's address.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
struct MyActor;
|
struct MyActor;
|
||||||
@ -43,44 +38,26 @@ impl Actor for MyActor {
|
|||||||
|
|
||||||
## Message
|
## Message
|
||||||
|
|
||||||
To be able to handle a specific message the actor has to provide a
|
To be able to handle a specific message the actor has to provide a [`Handler<M>`] implementation for this message. All messages are statically typed. The message can be handled in an asynchronous fashion. The actor can spawn other actors or add futures or streams to the execution context. The actor trait provides several methods that allow controlling the actor's lifecycle.
|
||||||
[`Handler<M>`] implementation for this message.
|
|
||||||
All messages are statically typed. The message can be handled in an asynchronous
|
|
||||||
fashion. The actor can spawn other actors or add futures or
|
|
||||||
streams to the execution context. The actor trait provides several methods that allow
|
|
||||||
controlling the actor's lifecycle.
|
|
||||||
|
|
||||||
To send a message to an actor, the `Addr` object needs to be used. `Addr` provides several
|
To send a message to an actor, the `Addr` object needs to be used. `Addr` provides several ways to send a message.
|
||||||
ways to send a message.
|
|
||||||
|
|
||||||
* `Addr::do_send(M)` - this method ignores any errors in message sending. If the mailbox
|
- `Addr::do_send(M)` - this method ignores any errors in message sending. If the mailbox is full the message is still queued, bypassing the limit. If the actor's mailbox is closed, the message is silently dropped. This method does not return the result, so if the mailbox is closed and a failure occurs, you won't have an indication of this.
|
||||||
is full the message is still queued, bypassing the limit. If the actor's mailbox is closed,
|
|
||||||
the message is silently dropped. This method does not return the result, so if the
|
|
||||||
mailbox is closed and a failure occurs, you won't have an indication of this.
|
|
||||||
|
|
||||||
* `Addr::try_send(M)` - this method tries to send the message immediately. If
|
- `Addr::try_send(M)` - this method tries to send the message immediately. If the mailbox is full or closed (actor is dead), this method returns a [`SendError`].
|
||||||
the mailbox is full or closed (actor is dead), this method returns a
|
|
||||||
[`SendError`].
|
|
||||||
|
|
||||||
* `Addr::send(M)` - This message returns a future object that resolves to a result
|
- `Addr::send(M)` - This message returns a future object that resolves to a result of a message handling process. If the returned `Future` object is dropped, the message is cancelled.
|
||||||
of a message handling process. If the returned `Future` object is dropped, the
|
|
||||||
message is cancelled.
|
|
||||||
|
|
||||||
[`Handler<M>`]: https://docs.rs/actix/latest/actix/trait.Handler.html
|
[`Handler<M>`]: https://docs.rs/actix/latest/actix/trait.Handler.html
|
||||||
[`SendError`]: https://docs.rs/actix/latest/actix/prelude/enum.SendError.html
|
[`SendError`]: https://docs.rs/actix/latest/actix/prelude/enum.SendError.html
|
||||||
|
|
||||||
## Recipient
|
## Recipient
|
||||||
|
|
||||||
Recipient is a specialized version of an address that supports only one type of message.
|
Recipient is a specialized version of an address that supports only one type of message. It can be used in case the message needs to be sent to a different type of actor. A recipient object can be created from an address with `Addr::recipient()`.
|
||||||
It can be used in case the message needs to be sent to a different type of actor.
|
|
||||||
A recipient object can be created from an address with `Addr::recipient()`.
|
|
||||||
|
|
||||||
Address objects require an actor type, but if we just want to send a specific message
|
Address objects require an actor type, but if we just want to send a specific message to an actor that can handle the message, we can use the Recipient interface.
|
||||||
to an actor that can handle the message, we can use the Recipient interface.
|
|
||||||
|
|
||||||
For example recipient can be used for a subscription system. In the following example
|
For example recipient can be used for a subscription system. In the following example `OrderEvents` actor sends a `OrderShipped` message to all subscribers. A subscriber can be any actor that implements the `Handler<OrderShipped>` trait.
|
||||||
`OrderEvents` actor sends a `OrderShipped` message to all subscribers. A subscriber can
|
|
||||||
be any actor that implements the `Handler<OrderShipped>` trait.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
@ -5,16 +5,11 @@ slug: /actix/context
|
|||||||
|
|
||||||
# Context
|
# Context
|
||||||
|
|
||||||
Actors all maintain an internal execution context, or state. This
|
Actors all maintain an internal execution context, or state. This allows an actor to determine its own Address, change mailbox limits, or stop its execution.
|
||||||
allows an actor to determine its own Address, change mailbox limits,
|
|
||||||
or stop its execution.
|
|
||||||
|
|
||||||
## Mailbox
|
## Mailbox
|
||||||
|
|
||||||
All messages go to the actor's mailbox first, then the actor's execution context
|
All messages go to the actor's mailbox first, then the actor's execution context calls specific message handlers. Mailboxes in general are bounded. The capacity is specific to the context implementation. For the `Context` type the capacity is set to 16 messages by default and can be increased with [`Context::set_mailbox_capacity()`].
|
||||||
calls specific message handlers. Mailboxes in general are bounded. The capacity is
|
|
||||||
specific to the context implementation. For the `Context` type the capacity is set to
|
|
||||||
16 messages by default and can be increased with [`Context::set_mailbox_capacity()`].
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
struct MyActor;
|
struct MyActor;
|
||||||
@ -30,18 +25,13 @@ impl Actor for MyActor {
|
|||||||
let addr = MyActor.start();
|
let addr = MyActor.start();
|
||||||
```
|
```
|
||||||
|
|
||||||
Remember that this doesn't apply to `Addr::do_send(M)` which bypasses the Mailbox queue limit, or
|
Remember that this doesn't apply to `Addr::do_send(M)` which bypasses the Mailbox queue limit, or `AsyncContext::notify(M)` and `AsyncContext::notify_later(M, Duration)` which bypasses the mailbox entirely.
|
||||||
`AsyncContext::notify(M)` and `AsyncContext::notify_later(M, Duration)` which bypasses the mailbox
|
|
||||||
entirely.
|
|
||||||
|
|
||||||
[`Context::set_mailbox_capacity()`]: https://docs.rs/actix/latest/actix/struct.Context.html#method.set_mailbox_capacity
|
[`Context::set_mailbox_capacity()`]: https://docs.rs/actix/latest/actix/struct.Context.html#method.set_mailbox_capacity
|
||||||
|
|
||||||
## Getting your actors Address
|
## Getting your actors Address
|
||||||
|
|
||||||
An actor can view its own address from its context. Perhaps you want to requeue an event for
|
An actor can view its own address from its context. Perhaps you want to requeue an event for later, or you want to transform the message type. Maybe you want to respond with your address to a message. If you want an actor to send a message to itself, have a look at `AsyncContext::notify(M)` instead.
|
||||||
later, or you want to transform the message type. Maybe you want to respond with your address
|
|
||||||
to a message. If you want an actor to send a message to itself, have a look at
|
|
||||||
`AsyncContext::notify(M)` instead.
|
|
||||||
|
|
||||||
To get your address from the context you call [`Context::address()`]. An example is:
|
To get your address from the context you call [`Context::address()`]. An example is:
|
||||||
|
|
||||||
@ -73,9 +63,7 @@ let who_addr = addr.do_send(WhoAmI{});
|
|||||||
|
|
||||||
## Stopping an Actor
|
## Stopping an Actor
|
||||||
|
|
||||||
From within the actors execution context you can choose to stop the actor from processing
|
From within the actors execution context you can choose to stop the actor from processing any future Mailbox messages. This could be in response to an error condition, or as part of program shutdown. To do this you call [`Context::stop()`].
|
||||||
any future Mailbox messages. This could be in response to an error condition, or as part
|
|
||||||
of program shutdown. To do this you call [`Context::stop()`].
|
|
||||||
|
|
||||||
This is an adjusted Ping example that stops after 4 pings are received.
|
This is an adjusted Ping example that stops after 4 pings are received.
|
||||||
|
|
||||||
|
@ -5,51 +5,27 @@ slug: /actix/arbiter
|
|||||||
|
|
||||||
# Arbiter
|
# Arbiter
|
||||||
|
|
||||||
`Arbiter`s provide an asynchronous execution context for `Actor`s, `functions` and `futures`. Where an
|
`Arbiter`s provide an asynchronous execution context for `Actor`s, `functions` and `futures`. Where an actor contains a `Context` that defines its Actor specific execution state, Arbiters host the environment where an actor runs.
|
||||||
actor contains a `Context` that defines its Actor specific execution state,
|
|
||||||
Arbiters host the environment where an actor runs.
|
|
||||||
|
|
||||||
As a result Arbiters perform a number of functions. Most notably, they are able
|
As a result Arbiters perform a number of functions. Most notably, they are able to spawn a new OS thread, run an event loop, spawn tasks asynchronously on that event loop, and act as helpers for asynchronous tasks.
|
||||||
to spawn a new OS thread, run an event loop, spawn tasks asynchronously on that
|
|
||||||
event loop, and act as helpers for asynchronous tasks.
|
|
||||||
|
|
||||||
## System and Arbiter
|
## System and Arbiter
|
||||||
|
|
||||||
In all our previous code examples the function `System::new` creates an Arbiter
|
In all our previous code examples the function `System::new` creates an Arbiter for your actors to run inside. When you call `start()` on your actor it is then running inside of the System Arbiter's thread. In many cases, this is all you will need for a program using Actix.
|
||||||
for your actors to run inside. When you call `start()` on your actor it is then
|
|
||||||
running inside of the System Arbiter's thread. In many cases, this is all you
|
|
||||||
will need for a program using Actix.
|
|
||||||
|
|
||||||
While it only uses one thread, it uses the very efficient event loop pattern
|
While it only uses one thread, it uses the very efficient event loop pattern which works well for asynchronous events. To handle synchronous, CPU-bound tasks, it's better to avoid blocking the event loop and instead offload the computation to other threads. For this usecase, read the next section and consider using [`SyncArbiter`](./sync-arbiter).
|
||||||
which works well for asynchronous events. To handle synchronous, CPU-bound
|
|
||||||
tasks, it's better to avoid blocking the event loop and instead offload the
|
|
||||||
computation to other threads. For this usecase, read the next section and
|
|
||||||
consider using [`SyncArbiter`](./sync-arbiter).
|
|
||||||
|
|
||||||
## The event loop
|
## The event loop
|
||||||
|
|
||||||
One `Arbiter` is in control of one thread with one event pool. When an Arbiter
|
One `Arbiter` is in control of one thread with one event pool. When an Arbiter spawns a task (via `Arbiter::spawn`, `Context<Actor>::run_later`, or similar constructs), the Arbiter queues the task for execution on that task queue. When you think `Arbiter`, you can think "single-threaded event loop".
|
||||||
spawns a task (via `Arbiter::spawn`, `Context<Actor>::run_later`, or similar
|
|
||||||
constructs), the Arbiter queues the task for execution on that task queue. When
|
|
||||||
you think `Arbiter`, you can think "single-threaded event loop".
|
|
||||||
|
|
||||||
Actix in general does support concurrency, but normal `Arbiter`s (not
|
Actix in general does support concurrency, but normal `Arbiter`s (not `SyncArbiter`s) do not. To use Actix in a concurrent way, you can spin up multiple `Arbiter`s using `Arbiter::new`, `ArbiterBuilder`, or `Arbiter::start`.
|
||||||
`SyncArbiter`s) do not. To use Actix in a concurrent way, you can spin up
|
|
||||||
multiple `Arbiter`s using `Arbiter::new`, `ArbiterBuilder`, or `Arbiter::start`.
|
|
||||||
|
|
||||||
When you create a new Arbiter, this creates a new execution context for Actors.
|
When you create a new Arbiter, this creates a new execution context for Actors. The new thread is available to add new Actors to it, but Actors cannot freely move between Arbiters: they are tied to the Arbiter they were spawned in. However, Actors on different Arbiters can still communicate with each other using the normal `Addr`/`Recipient` methods. The method of passing messages is agnostic to whether the Actors are running on the same or different Arbiters.
|
||||||
The new thread is available to add new Actors to it, but Actors cannot freely
|
|
||||||
move between Arbiters: they are tied to the Arbiter they were spawned in.
|
|
||||||
However, Actors on different Arbiters can still communicate with each other
|
|
||||||
using the normal `Addr`/`Recipient` methods. The method of passing messages is
|
|
||||||
agnostic to whether the Actors are running on the same or different Arbiters.
|
|
||||||
|
|
||||||
## Using Arbiter for resolving async events
|
## Using Arbiter for resolving async events
|
||||||
|
|
||||||
If you aren't an expert in Rust Futures, Arbiter can be a helpful and simple
|
If you aren't an expert in Rust Futures, Arbiter can be a helpful and simple wrapper to resolving async events in order. Consider we have two actors, A and B, and we want to run an event on B only once a result from A is completed. We can use `Arbiter::spawn` to assist with this task.
|
||||||
wrapper to resolving async events in order. Consider we have two actors, A and
|
|
||||||
B, and we want to run an event on B only once a result from A is completed. We
|
|
||||||
can use `Arbiter::spawn` to assist with this task.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
@ -5,22 +5,15 @@ slug: /actix/sync-arbiter
|
|||||||
|
|
||||||
# SyncArbiter
|
# SyncArbiter
|
||||||
|
|
||||||
When you normally run Actors, there are multiple Actors running on the
|
When you normally run Actors, there are multiple Actors running on the System's Arbiter thread, using its event loop. However for CPU bound workloads, or highly concurrent workloads, you may wish to have an Actor running multiple instances in parallel.
|
||||||
System's Arbiter thread, using its event loop. However for CPU bound workloads,
|
|
||||||
or highly concurrent workloads, you may wish to have an Actor running multiple
|
|
||||||
instances in parallel.
|
|
||||||
|
|
||||||
This is what a SyncArbiter provides - the ability to launch multiple instances of
|
This is what a SyncArbiter provides - the ability to launch multiple instances of an Actor on a pool of OS threads.
|
||||||
an Actor on a pool of OS threads.
|
|
||||||
|
|
||||||
It's important to note a SyncArbiter can only host a single type of Actor. This means
|
It's important to note a SyncArbiter can only host a single type of Actor. This means you need to create a SyncArbiter for each type of Actor you want to run in this manner.
|
||||||
you need to create a SyncArbiter for each type of Actor you want to run in this
|
|
||||||
manner.
|
|
||||||
|
|
||||||
## Creating a Sync Actor
|
## Creating a Sync Actor
|
||||||
|
|
||||||
When implementing your Actor to be run on a SyncArbiter, it requires that your Actor's
|
When implementing your Actor to be run on a SyncArbiter, it requires that your Actor's Context is changed from `Context` to `SyncContext`.
|
||||||
Context is changed from `Context` to `SyncContext`.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
@ -34,9 +27,7 @@ impl Actor for MySyncActor {
|
|||||||
|
|
||||||
## Starting the Sync Arbiter
|
## Starting the Sync Arbiter
|
||||||
|
|
||||||
Now that we have defined a Sync Actor, we can run it on a thread pool, created by
|
Now that we have defined a Sync Actor, we can run it on a thread pool, created by our `SyncArbiter`. We can only control the number of threads at SyncArbiter creation time - we can't add/remove threads later.
|
||||||
our `SyncArbiter`. We can only control the number of threads at SyncArbiter creation
|
|
||||||
time - we can't add/remove threads later.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
@ -50,10 +41,8 @@ impl Actor for MySyncActor {
|
|||||||
let addr = SyncArbiter::start(2, || MySyncActor);
|
let addr = SyncArbiter::start(2, || MySyncActor);
|
||||||
```
|
```
|
||||||
|
|
||||||
We can communicate with the addr the same way as we have with our previous Actors
|
We can communicate with the addr the same way as we have with our previous Actors that we started. We can send messages, receive futures and results, and more.
|
||||||
that we started. We can send messages, receive futures and results, and more.
|
|
||||||
|
|
||||||
## Sync Actor Mailboxes
|
## Sync Actor Mailboxes
|
||||||
|
|
||||||
Sync Actors have no Mailbox limits, but you should still use `do_send`, `try_send` and `send`
|
Sync Actors have no Mailbox limits, but you should still use `do_send`, `try_send` and `send` as normal to account for other possible errors or sync vs async behavior.
|
||||||
as normal to account for other possible errors or sync vs async behavior.
|
|
||||||
|
@ -49,6 +49,7 @@ and register the data in an `App`:
|
|||||||
<CodeBlock example="application" file="mutable_state.rs" section="make_app_mutable" />
|
<CodeBlock example="application" file="mutable_state.rs" section="make_app_mutable" />
|
||||||
|
|
||||||
Key takeaways:
|
Key takeaways:
|
||||||
|
|
||||||
- State initialized _inside_ the closure passed to `HttpServer::new` is local to the worker thread and may become de-synced if modified.
|
- State initialized _inside_ the closure passed to `HttpServer::new` is local to the worker thread and may become de-synced if modified.
|
||||||
- To achieve _globally shared state_, it must be created **outside** of the closure passed to `HttpServer::new` and moved/cloned in.
|
- To achieve _globally shared state_, it must be created **outside** of the closure passed to `HttpServer::new` and moved/cloned in.
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ During development it can be very handy to have cargo automatically recompile th
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo watch -x run
|
cargo watch -x run
|
||||||
```
|
```
|
||||||
|
|
||||||
## Historical Note
|
## Historical Note
|
||||||
|
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
title: Getting Started
|
title: Getting Started
|
||||||
---
|
---
|
||||||
|
|
||||||
import RenderCodeBlock from '@theme/CodeBlock';
|
import RenderCodeBlock from '@theme/CodeBlock'; import CodeBlock from "@site/src/components/code_block.js"; import { rustVersion, actixWebMajorVersion } from "@site/vars";
|
||||||
import CodeBlock from "@site/src/components/code_block.js";
|
|
||||||
import { rustVersion, actixWebMajorVersion } from "@site/vars";
|
|
||||||
|
|
||||||
## Installing Rust
|
## Installing Rust
|
||||||
|
|
||||||
@ -25,7 +23,6 @@ cd hello-world
|
|||||||
|
|
||||||
Add `actix-web` as a dependency of your project by adding the following to your `Cargo.toml` file.
|
Add `actix-web` as a dependency of your project by adding the following to your `Cargo.toml` file.
|
||||||
|
|
||||||
|
|
||||||
<!-- DEPENDENCY -->
|
<!-- DEPENDENCY -->
|
||||||
|
|
||||||
<RenderCodeBlock className="language-toml">
|
<RenderCodeBlock className="language-toml">
|
||||||
|
@ -2,11 +2,9 @@
|
|||||||
title: HTTP/2
|
title: HTTP/2
|
||||||
---
|
---
|
||||||
|
|
||||||
import RenderCodeBlock from '@theme/CodeBlock';
|
import RenderCodeBlock from '@theme/CodeBlock'; import CodeBlock from '@site/src/components/code_block.js'; import { actixWebMajorVersion } from "@site/vars";
|
||||||
import CodeBlock from '@site/src/components/code_block.js';
|
|
||||||
import { actixWebMajorVersion } from "@site/vars";
|
|
||||||
|
|
||||||
`actix-web` automatically upgrades connections to *HTTP/2* if possible.
|
`actix-web` automatically upgrades connections to _HTTP/2_ if possible.
|
||||||
|
|
||||||
# Negotiation
|
# Negotiation
|
||||||
|
|
||||||
@ -16,7 +14,6 @@ When either of the `rustls` or `openssl` features are enabled, `HttpServer` prov
|
|||||||
|
|
||||||
<!-- DEPENDENCY -->
|
<!-- DEPENDENCY -->
|
||||||
|
|
||||||
|
|
||||||
<RenderCodeBlock className="language-toml">
|
<RenderCodeBlock className="language-toml">
|
||||||
{`[dependencies]
|
{`[dependencies]
|
||||||
actix-web = { version = "${actixWebMajorVersion}", features = ["openssl"] }
|
actix-web = { version = "${actixWebMajorVersion}", features = ["openssl"] }
|
||||||
|
@ -90,6 +90,7 @@ A _signed_ cookie may be viewed but not modified by the client. A _private_ cook
|
|||||||
The constructors take a key as an argument. This is the private key for cookie session - when this value is changed, all session data is lost.
|
The constructors take a key as an argument. This is the private key for cookie session - when this value is changed, all session data is lost.
|
||||||
|
|
||||||
In general, you create a `SessionStorage` middleware and initialize it with specific backend implementation, such as a `CookieSession`. To access session data the [`Session`][requestsession] extractor must be used. This method returns a [_Session_][sessionobj] object, which allows us to get or set session data.
|
In general, you create a `SessionStorage` middleware and initialize it with specific backend implementation, such as a `CookieSession`. To access session data the [`Session`][requestsession] extractor must be used. This method returns a [_Session_][sessionobj] object, which allows us to get or set session data.
|
||||||
|
|
||||||
> `actix_session::storage::CookieSessionStore` is available on the crate feature "cookie-session".
|
> `actix_session::storage::CookieSessionStore` is available on the crate feature "cookie-session".
|
||||||
|
|
||||||
<CodeBlock example="middleware" file="user_sessions.rs" section="user-session" />
|
<CodeBlock example="middleware" file="user_sessions.rs" section="user-session" />
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
title: Server
|
title: Server
|
||||||
---
|
---
|
||||||
|
|
||||||
import RenderCodeBlock from '@theme/CodeBlock';
|
import RenderCodeBlock from '@theme/CodeBlock'; import CodeBlock from '@site/src/components/code_block.js'; import { actixWebMajorVersion } from "@site/vars";
|
||||||
import CodeBlock from '@site/src/components/code_block.js';
|
|
||||||
import { actixWebMajorVersion } from "@site/vars";
|
|
||||||
|
|
||||||
# The HTTP Server
|
# The HTTP Server
|
||||||
|
|
||||||
|
@ -10,10 +10,7 @@ It is possible to serve static files with a custom path pattern and `NamedFile`.
|
|||||||
|
|
||||||
<CodeBlock example="static-files" file="main.rs" section="individual-file" />
|
<CodeBlock example="static-files" file="main.rs" section="individual-file" />
|
||||||
|
|
||||||
:::warning
|
:::warning Matching a path tail with the `[.*]` regex and using it to return a `NamedFile` has serious security implications. It offers the possibility for an attacker to insert `../` into the URL and access every file on the host that the user running the server has access to. :::
|
||||||
Matching a path tail with the `[.*]` regex and using it to return a `NamedFile` has serious security implications.
|
|
||||||
It offers the possibility for an attacker to insert `../` into the URL and access every file on the host that the user running the server has access to.
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Directory
|
## Directory
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ Actix Web supports WebSockets with the `actix-web-actors` crate. It is possible
|
|||||||
|
|
||||||
The following is an example of a simple websocket echo server:
|
The following is an example of a simple websocket echo server:
|
||||||
|
|
||||||
|
|
||||||
<CodeBlock example="websockets" file="main.rs" section="websockets" />
|
<CodeBlock example="websockets" file="main.rs" section="websockets" />
|
||||||
|
|
||||||
> A simple websocket echo server example is available in the [examples directory][examples].
|
> A simple websocket echo server example is available in the [examples directory][examples].
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: What is Actix Web
|
title: What is Actix Web
|
||||||
---
|
---
|
||||||
|
|
||||||
import { rustVersion } from "@site/vars";
|
import { rustVersion } from "@site/vars";
|
||||||
|
|
||||||
# Actix Web is part of an Ecosystem of Crates
|
# Actix Web is part of an Ecosystem of Crates
|
||||||
|
Loading…
Reference in New Issue
Block a user