Networking
From Internet Computer Wiki
Networking designs
Preventing server overload
Rust async
Quick Tips
- Avoid creating new instances of tokio::runtime::Runtime in situ. Parameterize your component over tokio::runtime::Handle and pass the handle of the top-level runtime in the main function.
- Avoid blocking the event thread for a long time by calling computationally-expensive or blocking functions in your futures. In case of an HTTP server, it almost always makes sense to off-load the actual request handling to a thread pool.
- Avoid calling tokio::runtime::Runtime::block_on in your async components. This makes it impossible to use your components in other async code. It is fine to call block_on from a sync component as long as blocking the thread until a result is available is allowed. For example, calling a gRPC service with requests that have deadline/timeout specified.
- Never use tokio::task::block_in_place. Using this function almost always signals that there is an issue with the overall design.
- Never call std::thread::sleep in async code. If you really have to suspend current task for a while, use tokio::time::sleep instead.
- Avoid using sleep (both sync and async) for synchronization, It's often a sign of flawed component communication pattern. Use callbacks, tokio synchronization and communication primitives instead. There are valid use-cases for sleep, but they mostly apply to events happening outside of the current process, e.g., like waiting for a remote service to get back to life.
- Never hold std::sync::Mutex or parking_lot::Mutex across .await points. Holding a Mutex across .await points never leads to correct concurrent code. In practice this can easily lead to deadlocks. More information about picking the right mutex can be found in the tokio’s docs.