mirror of
https://github.com/actix/actix-website
synced 2024-11-23 16:31:08 +01:00
prettier markdown
This commit is contained in:
parent
7c4b52623e
commit
0d0e7f4433
@ -1,6 +1,6 @@
|
||||
singleQuote: true
|
||||
tabWidth: 2
|
||||
overrides:
|
||||
- files: ["*.md"]
|
||||
options:
|
||||
proseWrap: never
|
||||
- files: ['*.md']
|
||||
options:
|
||||
proseWrap: never
|
||||
printWidth: 9999
|
||||
|
@ -5,8 +5,7 @@ slug: /actix
|
||||
|
||||
# Quick start
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Install Rust
|
||||
|
||||
@ -26,9 +25,7 @@ The actix framework requires Rust version 1.40.0 and up.
|
||||
|
||||
## Running Examples
|
||||
|
||||
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:
|
||||
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:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/actix/actix
|
||||
|
@ -5,23 +5,20 @@ slug: /actix/getting-started
|
||||
|
||||
# Getting Started
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
In previous section we already installed required rust version. Now let's create new cargo projects.
|
||||
|
||||
## Ping actor
|
||||
|
||||
Let’s write our first actix application! Start by creating a new binary-based
|
||||
Cargo project and changing into the new directory:
|
||||
Let’s write our first actix application! Start by creating a new binary-based Cargo project and changing into the new directory:
|
||||
|
||||
```bash
|
||||
cargo new actor-ping
|
||||
cd actor-ping
|
||||
```
|
||||
|
||||
Now, add actix as a dependency of your project by ensuring your Cargo.toml
|
||||
contains the following:
|
||||
Now, add actix as a dependency of your project by ensuring your Cargo.toml contains the following:
|
||||
|
||||
```toml
|
||||
[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
|
||||
on actor contexts is available in the next section.
|
||||
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.
|
||||
|
||||
Now we need to define the `Message` that the actor needs to accept. The message can be any type
|
||||
that implements the `Message` trait.
|
||||
Now we need to define the `Message` that the actor needs to accept. The message can be any type that implements the `Message` trait.
|
||||
|
||||
```rust
|
||||
use actix::prelude::*;
|
||||
@ -59,12 +54,9 @@ use actix::prelude::*;
|
||||
struct Ping(usize);
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
```rust
|
||||
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.
|
||||
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()`.
|
||||
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()`.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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
|
||||
so we can easily `.await` for the messages sent to the Actor.
|
||||
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.
|
||||
|
||||
```rust
|
||||
#[actix_rt::main]
|
||||
|
@ -7,26 +7,15 @@ slug: /actix/actor
|
||||
|
||||
Actix is a rust library providing a framework for developing concurrent applications.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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
|
||||
[`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.
|
||||
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.
|
||||
|
||||
[Actor Model]: https://en.wikipedia.org/wiki/Actor_model
|
||||
[`Context<A>`]: ./context
|
||||
@ -37,46 +26,33 @@ The `Actor` trait provides several methods that allow controlling the actor's li
|
||||
|
||||
### 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.
|
||||
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.
|
||||
|
||||
### Running
|
||||
|
||||
After an Actor's `started()` method is called, the actor transitions to the `Running` state.
|
||||
The Actor can stay in `running` state indefinitely.
|
||||
After an Actor's `started()` method is called, the actor transitions to the `Running` state. The Actor can stay in `running` state indefinitely.
|
||||
|
||||
### Stopping
|
||||
|
||||
The Actor's execution state changes to the `stopping` state in the following situations:
|
||||
|
||||
* `Context::stop` is called by the actor itself
|
||||
* all addresses to the actor get dropped. i.e. no other actor references it.
|
||||
* no event objects are registered in the context.
|
||||
- `Context::stop` is called by the actor itself
|
||||
- all addresses to the actor get dropped. i.e. no other actor references it.
|
||||
- no event objects are registered in the context.
|
||||
|
||||
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`.
|
||||
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`.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
By default this method returns `Running::Stop` which confirms the stop operation.
|
||||
|
||||
### Stopped
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Message
|
||||
|
||||
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>`.
|
||||
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>`.
|
||||
|
||||
```rust
|
||||
use actix::prelude::*;
|
||||
@ -92,10 +68,7 @@ impl Message for Ping {
|
||||
|
||||
## Spawning an 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.
|
||||
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.
|
||||
|
||||
## Complete example
|
||||
|
||||
@ -152,10 +125,7 @@ async fn main() {
|
||||
|
||||
## Responding with a MessageResponse
|
||||
|
||||
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:
|
||||
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:
|
||||
|
||||
```rust
|
||||
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
|
||||
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.
|
||||
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.
|
||||
|
||||
```rust
|
||||
use actix::dev::{MessageResponse, OneshotSender};
|
||||
|
@ -5,15 +5,11 @@ slug: /actix/address
|
||||
|
||||
# Address
|
||||
|
||||
Actors communicate exclusively by exchanging messages. The sending actor can optionally
|
||||
wait for the response. Actors cannot be referenced directly, only by their addresses.
|
||||
Actors communicate exclusively by exchanging messages. The sending actor can optionally 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
|
||||
two helper methods for starting an actor. Both return the address of the started actor.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
```rust
|
||||
struct MyActor;
|
||||
@ -24,8 +20,7 @@ impl Actor for MyActor {
|
||||
let addr = MyActor.start();
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
```rust
|
||||
struct MyActor;
|
||||
@ -43,44 +38,26 @@ impl Actor for MyActor {
|
||||
|
||||
## Message
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
To send a message to an actor, the `Addr` object needs to be used. `Addr` provides several
|
||||
ways to send a message.
|
||||
To send a message to an actor, the `Addr` object needs to be used. `Addr` provides several ways to send a message.
|
||||
|
||||
* `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.
|
||||
- `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.
|
||||
|
||||
* `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`].
|
||||
- `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`].
|
||||
|
||||
* `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.
|
||||
- `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.
|
||||
|
||||
[`Handler<M>`]: https://docs.rs/actix/latest/actix/trait.Handler.html
|
||||
[`SendError`]: https://docs.rs/actix/latest/actix/prelude/enum.SendError.html
|
||||
|
||||
## Recipient
|
||||
|
||||
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()`.
|
||||
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()`.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
```rust
|
||||
use actix::prelude::*;
|
||||
|
@ -5,16 +5,11 @@ slug: /actix/context
|
||||
|
||||
# Context
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Mailbox
|
||||
|
||||
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()`].
|
||||
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()`].
|
||||
|
||||
```rust
|
||||
struct MyActor;
|
||||
@ -30,18 +25,13 @@ impl Actor for MyActor {
|
||||
let addr = MyActor.start();
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
[`Context::set_mailbox_capacity()`]: https://docs.rs/actix/latest/actix/struct.Context.html#method.set_mailbox_capacity
|
||||
|
||||
## Getting your actors Address
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
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()`].
|
||||
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()`].
|
||||
|
||||
This is an adjusted Ping example that stops after 4 pings are received.
|
||||
|
||||
|
@ -5,51 +5,27 @@ slug: /actix/arbiter
|
||||
|
||||
# Arbiter
|
||||
|
||||
`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.
|
||||
`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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## System and 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.
|
||||
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.
|
||||
|
||||
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).
|
||||
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).
|
||||
|
||||
## The event loop
|
||||
|
||||
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".
|
||||
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".
|
||||
|
||||
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`.
|
||||
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`.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Using Arbiter for resolving async events
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
```rust
|
||||
use actix::prelude::*;
|
||||
|
@ -5,22 +5,15 @@ slug: /actix/sync-arbiter
|
||||
|
||||
# SyncArbiter
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
This is what a SyncArbiter provides - the ability to launch multiple instances of
|
||||
an Actor on a pool of OS threads.
|
||||
This is what a SyncArbiter provides - the ability to launch multiple instances of 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
|
||||
you need to create a SyncArbiter for each type of Actor you want to run in this
|
||||
manner.
|
||||
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.
|
||||
|
||||
## Creating a Sync Actor
|
||||
|
||||
When implementing your Actor to be run on a SyncArbiter, it requires that your Actor's
|
||||
Context is changed from `Context` to `SyncContext`.
|
||||
When implementing your Actor to be run on a SyncArbiter, it requires that your Actor's Context is changed from `Context` to `SyncContext`.
|
||||
|
||||
```rust
|
||||
use actix::prelude::*;
|
||||
@ -34,9 +27,7 @@ impl Actor for MySyncActor {
|
||||
|
||||
## Starting the Sync Arbiter
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
```rust
|
||||
use actix::prelude::*;
|
||||
@ -50,10 +41,8 @@ impl Actor for MySyncActor {
|
||||
let addr = SyncArbiter::start(2, || MySyncActor);
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Sync Actor Mailboxes
|
||||
|
||||
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.
|
||||
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.
|
||||
|
@ -49,6 +49,7 @@ and register the data in an `App`:
|
||||
<CodeBlock example="application" file="mutable_state.rs" section="make_app_mutable" />
|
||||
|
||||
Key takeaways:
|
||||
|
||||
- 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.
|
||||
|
||||
|
@ -8,7 +8,7 @@ During development it can be very handy to have cargo automatically recompile th
|
||||
|
||||
```sh
|
||||
cargo watch -x run
|
||||
```
|
||||
```
|
||||
|
||||
## Historical Note
|
||||
|
||||
|
@ -2,9 +2,7 @@
|
||||
title: Getting Started
|
||||
---
|
||||
|
||||
import RenderCodeBlock from '@theme/CodeBlock';
|
||||
import CodeBlock from "@site/src/components/code_block.js";
|
||||
import { rustVersion, actixWebMajorVersion } from "@site/vars";
|
||||
import RenderCodeBlock from '@theme/CodeBlock'; import CodeBlock from "@site/src/components/code_block.js"; import { rustVersion, actixWebMajorVersion } from "@site/vars";
|
||||
|
||||
## 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.
|
||||
|
||||
|
||||
<!-- DEPENDENCY -->
|
||||
|
||||
<RenderCodeBlock className="language-toml">
|
||||
|
@ -2,11 +2,9 @@
|
||||
title: HTTP/2
|
||||
---
|
||||
|
||||
import RenderCodeBlock from '@theme/CodeBlock';
|
||||
import CodeBlock from '@site/src/components/code_block.js';
|
||||
import { actixWebMajorVersion } from "@site/vars";
|
||||
import RenderCodeBlock from '@theme/CodeBlock'; 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
|
||||
|
||||
@ -16,7 +14,6 @@ When either of the `rustls` or `openssl` features are enabled, `HttpServer` prov
|
||||
|
||||
<!-- DEPENDENCY -->
|
||||
|
||||
|
||||
<RenderCodeBlock className="language-toml">
|
||||
{`[dependencies]
|
||||
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.
|
||||
|
||||
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".
|
||||
|
||||
<CodeBlock example="middleware" file="user_sessions.rs" section="user-session" />
|
||||
|
@ -2,9 +2,7 @@
|
||||
title: Server
|
||||
---
|
||||
|
||||
import RenderCodeBlock from '@theme/CodeBlock';
|
||||
import CodeBlock from '@site/src/components/code_block.js';
|
||||
import { actixWebMajorVersion } from "@site/vars";
|
||||
import RenderCodeBlock from '@theme/CodeBlock'; import CodeBlock from '@site/src/components/code_block.js'; import { actixWebMajorVersion } from "@site/vars";
|
||||
|
||||
# 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" />
|
||||
|
||||
:::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.
|
||||
:::
|
||||
:::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. :::
|
||||
|
||||
## 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:
|
||||
|
||||
|
||||
<CodeBlock example="websockets" file="main.rs" section="websockets" />
|
||||
|
||||
> A simple websocket echo server example is available in the [examples directory][examples].
|
||||
|
@ -1,6 +1,7 @@
|
||||
---
|
||||
title: What is Actix Web
|
||||
---
|
||||
|
||||
import { rustVersion } from "@site/vars";
|
||||
|
||||
# Actix Web is part of an Ecosystem of Crates
|
||||
|
Loading…
Reference in New Issue
Block a user