tokio (1.54.1)
Overview
This skill holds what the official tokio docs say that is easy to get wrong: cancel safety, blocking the runtime, surprising defaults, panics and the APIs that replace old ones. Basics every async Rust developer knows are left out. Every claim in references/ ends with the docs URL it comes from, so you can reopen the page. https://docs.rs/tokio/latest/tokio/index.html
Version covered
tokio 1.54.1, as served by docs.rs/tokio/latest, plus the tokio.rs tutorial and topics pages. Unstable APIs need --cfg tokio_unstable and may break in 1.x, so do not suggest them unless the project already enables it. https://docs.rs/tokio/latest/tokio/index.html#unstable-features
How to navigate
- Find the domain of the code you write or review in the table below.
- Open only that reference file. Each one stands alone, with a table of contents at the top.
- Apply its default. Take the escape hatch only when the stated condition holds.
- In a review, also check the "Old patterns" table at the end of the file when there is one, and suggest the replacement.
- In your answer, give the docs URL that follows each rule you apply, so the reader can check it.
Highest-value rules
- A runtime built with
Builderhas no I/O or timer driver. Callenable_all(), or networking and time types fail. https://docs.rs/tokio/latest/tokio/runtime/index.html#resource-drivers #[tokio::test]runs on a current-thread runtime,#[tokio::main]on a multi-thread one.#[tokio::main]on a function called often builds a new runtime per call. https://docs.rs/tokio/latest/tokio/attr.test.html and https://docs.rs/tokio/latest/tokio/attr.main.htmlrt.block_on(sleep(d))panics: the future is created outside the runtime. Wrap it,rt.block_on(async { sleep(d).await }). https://docs.rs/tokio/latest/tokio/time/fn.sleep.html- On a current-thread runtime, spawned tasks run only while
Runtime::block_onruns.Handle::block_ondoes not drive it. https://docs.rs/tokio/latest/tokio/runtime/index.html#driving-the-runtime - Default to
std::sync::Mutexin async code, never held across.await. End the guard in a block scope, sincedrop(guard)does not satisfy theSendcheck. Usetokio::sync::Mutexonly when the guard must cross an.await. https://tokio.rs/tokio/tutorial/shared-state - Run blocking or CPU-heavy code with
spawn_blocking, and an endless loop on astd::thread.abortdoes not stop a running blocking task. https://docs.rs/tokio/latest/tokio/task/fn.spawn_blocking.html - In
select!, losing branches are dropped.read_exact,read_to_end,write_allandmpsc::Sender::sendlose data there. Usereserve()for sends, and pin long-lived futures outside the loop and select on&mut fut. https://docs.rs/tokio/latest/tokio/macro.select.html and https://docs.rs/tokio/latest/tokio/sync/mpsc/struct.Sender.html#method.send select!panics when every branch is disabled and there is noelse. https://docs.rs/tokio/latest/tokio/macro.select.html- Prefer a bounded
mpsc::channel(n)for backpressure.recvreturnsNoneonly once everySenderis dropped. https://tokio.rs/tokio/tutorial/channels and https://docs.rs/tokio/latest/tokio/sync/mpsc/index.html - A slow broadcast receiver gets
RecvError::Lagged(n)and stays open. Handle it instead of treating every error as closed. https://docs.rs/tokio/latest/tokio/sync/broadcast/struct.Receiver.html#method.recv - In a watch
changed()loop useborrow_and_update(), and never hold aborrow()across.await. https://docs.rs/tokio/latest/tokio/sync/watch/index.html - Dropping a
JoinHandledetaches the task. Dropping aJoinSetaborts all its tasks. https://docs.rs/tokio/latest/tokio/task/struct.JoinSet.html intervalticks immediately first and bursts missed ticks by default. SetMissedTickBehavior::DelayorSkipwhen catch-up bursts are wrong. https://docs.rs/tokio/latest/tokio/time/enum.MissedTickBehavior.htmltimeoutpolls the future before checking the deadline, so a future that never yields can finish past the deadline withOk. https://docs.rs/tokio/latest/tokio/time/fn.timeout.html- Test timers with
#[tokio::test(start_paused = true)](featuretest-util) andsleepwith auto-advance rather thanadvance. https://docs.rs/tokio/latest/tokio/time/fn.advance.html - Flush a
BufWriterand atokio::fs::Filebefore drop, or data is lost or written late. https://docs.rs/tokio/latest/tokio/io/index.html and https://docs.rs/tokio/latest/tokio/fs/struct.File.html - A
read()returningOk(0)means closed. A loop that ignores it spins at 100 % CPU. https://tokio.rs/tokio/tutorial/io - Every
tokio::fscall is onespawn_blocking. Batch withfs::read/fs::writeorBufWriter. https://docs.rs/tokio/latest/tokio/fs/index.html - A dropped
Childkeeps running unlesskill_on_drop(true).output()forces piped stdout and stderr. https://docs.rs/tokio/latest/tokio/process/index.html and https://docs.rs/tokio/latest/tokio/process/struct.Command.html#method.output - On Unix, the first
ctrl_c()listener replaces the default SIGINT handler for good. https://docs.rs/tokio/latest/tokio/signal/fn.ctrl_c.html - A named pipe server must create the next instance before handing off the connected one, or clients get
NotFound. A client retries only onERROR_PIPE_BUSY.NotFoundmeans no server, so return the error instead of retrying. https://docs.rs/tokio/latest/tokio/net/windows/named_pipe/struct.NamedPipeServer.html and https://docs.rs/tokio/latest/tokio/net/windows/named_pipe/struct.NamedPipeClient.html
References
| File | Covers |
|---|---|
| references/runtime.md | Feature flags, Builder and drivers, LocalRuntime, shutdown, #[tokio::main] and #[tokio::test] |
| references/block-on-bridging.md | Driving a runtime, block_on and Handle::block_on, EnterGuard and Handle::current, calling async code from sync code, Unix fork |
| references/tasks.md | spawn and its bounds, JoinHandle, abort, JoinSet, spawn_blocking, block_in_place, coop budget, LocalSet, spawn_local, task_local |
| references/sync-locks.md | std vs tokio Mutex, guards across .await, RwLock, Semaphore, Notify, OnceCell, SetOnce, Barrier |
| references/channels.md | mpsc backpressure, permits and closing, oneshot, broadcast lag, watch borrow rules |
| references/select-cancellation.md | select! rules, cancel safety lists, pinning across loops, biased, join!, try_join!, graceful shutdown |
| references/time-testing.md | sleep, interval and MissedTickBehavior, timeout, Instant, paused time, mocking I/O in tests |
| references/io-net.md | AsyncRead/AsyncWrite ext traits, BufWriter, split, io::copy, framing, TcpListener, TcpStream, TcpSocket, UdpSocket |
| references/fs-process.md | tokio::fs and its blocking pool, File flush and drop, Command, Child, kill_on_drop, stdio pipes |
| references/signals-named-pipes.md | ctrl_c, Unix signals, Windows console events, Windows named pipe server and client |
All pages read are listed in SOURCES.md.