diff --git a/content/tokio/topics/tracing-next-steps.md b/content/tokio/topics/tracing-next-steps.md index d6efebb4..2e4045ff 100644 --- a/content/tokio/topics/tracing-next-steps.md +++ b/content/tokio/topics/tracing-next-steps.md @@ -12,9 +12,8 @@ performance issues during the development process. For instance, to use tokio-console in [the mini-redis project](https://github.com/tokio-rs/mini-redis), you need to enable the `tracing` feature for the Tokio package: -```toml -# Update the tokio import in your Cargo.toml -tokio = { version = "1", features = ["full", "tracing"] } +```bash +cargo add tokio --features full,tracing ``` Note: The `full` feature doesn't enable `tracing`. @@ -23,9 +22,8 @@ You'll also need to add a dependency on the `console-subscriber` package. This crate provides a `Subscriber` implementation that will replace the one currently used by mini-redis: -```toml -# Add this to the dependencies section of your Cargo.toml -console-subscriber = "0.1.5" +```bash +cargo add console-subscriber ``` Finally, in `src/bin/server.rs`, replace the call to `tracing_subscriber` with @@ -128,16 +126,16 @@ It will look like this: We'll come back to this page once we have some trace data generated and sent. -To set up mini-redis, we'll first need to add a few dependencies. Update your -`Cargo.toml` with the following: +To set up mini-redis, we'll first need to add a few dependencies. Add the +following dependencies to your `Cargo.toml` file: -```toml +```bash # Implements the types defined in the Otel spec -opentelemetry = "0.17.0" +cargo add opentelemetry # Integration between the tracing crate and the opentelemetry crate -tracing-opentelemetry = "0.17.2" +cargo add tracing-opentelemetry # Allows you to export data to Jaeger -opentelemetry-jaeger = "0.16.0" +cargo add opentelemetry-jaeger ``` Now, in `src/bin/server.rs`, add the following imports: diff --git a/content/tokio/tutorial/async.md b/content/tokio/tutorial/async.md index 57216bab..5a395d63 100644 --- a/content/tokio/tutorial/async.md +++ b/content/tokio/tutorial/async.md @@ -499,10 +499,10 @@ implementors, but requires a bunch of unsafe boilerplate code. Instead of using provided by the [`futures`] crate. This allows us to implement a simple trait to expose our `Task` struct as a waker. -Add the following dependency to your `Cargo.toml` to pull in `futures`. +Add the `futures` dependency to your `Cargo.toml` file: -```toml -futures = "0.3" +```bash +cargo add futures ``` Then implement [`futures::task::ArcWake`][`ArcWake`]. diff --git a/content/tokio/tutorial/hello-tokio.md b/content/tokio/tutorial/hello-tokio.md index 72ff89e1..ea47b46c 100644 --- a/content/tokio/tutorial/hello-tokio.md +++ b/content/tokio/tutorial/hello-tokio.md @@ -13,17 +13,17 @@ then read back the key. This will be done using the Mini-Redis client library. Let's start by generating a new Rust app: ```bash -$ cargo new my-redis -$ cd my-redis +cargo new my-redis +cd my-redis ``` ## Add dependencies -Next, open `Cargo.toml` and add the following right below `[dependencies]`: +Next, add the following dependencies to your `Cargo.toml` file: -```toml -tokio = { version = "1", features = ["full"] } -mini-redis = "0.4" +```bash +cargo add tokio --features full +cargo add mini-redis ``` ## Write the code @@ -55,13 +55,13 @@ async fn main() -> Result<()> { Make sure the Mini-Redis server is running. In a separate terminal window, run: ```bash -$ mini-redis-server +mini-redis-server ``` If you have not already installed mini-redis, you can do so with ```bash -$ cargo install mini-redis +cargo install mini-redis ``` Now, run the `my-redis` application: diff --git a/content/tokio/tutorial/shared-state.md b/content/tokio/tutorial/shared-state.md index 7be04ce1..33a95a70 100644 --- a/content/tokio/tutorial/shared-state.md +++ b/content/tokio/tutorial/shared-state.md @@ -30,11 +30,10 @@ the underlying data. Instead, a `Bytes` instance is a reference-counted handle to some underlying data. The `Bytes` type is roughly an `Arc>` but with some added capabilities. -To depend on `bytes`, add the following to your `Cargo.toml` in the -`[dependencies]` section: +Add the `bytes` dependency to your `Cargo.toml` file: -```toml -bytes = "1" +```bash +cargo add bytes ``` [`bytes`]: https://docs.rs/bytes/1/bytes/struct.Bytes.html @@ -154,6 +153,7 @@ async fn process(socket: TcpStream, db: Db) { # Holding a `MutexGuard` across an `.await` You might write code that looks like this: + ```rust use std::sync::{Mutex, MutexGuard}; @@ -165,8 +165,10 @@ async fn increment_and_do_stuff(mutex: &Mutex) { } // lock goes out of scope here # async fn do_something_async() {} ``` + When you try to spawn something that calls this function, you will encounter the following error message: + ```text error: future cannot be sent between threads safely --> src/lib.rs:13:5 @@ -191,11 +193,13 @@ note: future is not `Send` as this value is used across an await 8 | } | - `mut lock` is later dropped here ``` + This happens because the `std::sync::MutexGuard` type is **not** `Send`. This means that you can't send a mutex lock to another thread, and the error happens because the Tokio runtime can move a task between threads at every `.await`. To avoid this, you should restructure your code such that the mutex lock's destructor runs before the `.await`. + ```rust # use std::sync::{Mutex, MutexGuard}; // This works! @@ -209,7 +213,9 @@ async fn increment_and_do_stuff(mutex: &Mutex) { } # async fn do_something_async() {} ``` + Note that this does not work: + ```rust use std::sync::{Mutex, MutexGuard}; @@ -223,6 +229,7 @@ async fn increment_and_do_stuff(mutex: &Mutex) { } # async fn do_something_async() {} ``` + This is because the compiler currently calculates whether a future is `Send` based on scope information only. The compiler will hopefully be updated to support explicitly dropping it in the future, but for now, you must explicitly @@ -250,6 +257,7 @@ We will discuss some approaches to avoid these issues below: The safest way to handle a mutex is to wrap it in a struct, and lock the mutex only inside non-async methods on that struct. + ```rust use std::sync::Mutex; @@ -270,6 +278,7 @@ async fn increment_and_do_stuff(can_incr: &CanIncrement) { } # async fn do_something_async() {} ``` + This pattern guarantees that you won't run into the `Send` error, because the mutex guard does not appear anywhere in an async function. It also protects you from deadlocks, when using crates whose `MutexGuard` implements `Send`. @@ -288,6 +297,7 @@ The [`tokio::sync::Mutex`] type provided by Tokio can also be used. The primary feature of the Tokio mutex is that it can be held across an `.await` without any issues. That said, an asynchronous mutex is more expensive than an ordinary mutex, and it is typically better to use one of the two other approaches. + ```rust use tokio::sync::Mutex; // note! This uses the Tokio mutex