Rust

Lesson 08

Async Send and Sync boundaries

Use thread-safe shared state around async tasks instead of holding non-Send values across await points.

Good Code

src/review_cache.rs
use std::sync::Arc;
use tokio::sync::RwLock;

pub async fn remember_review(cache: Arc<RwLock<Vec<Review>>>, review: Review) {
    // Async-aware locking keeps shared state safe across spawned tasks.
    let mut reviews = cache.write().await;
    reviews.push(review);
}

Bad Code

review_cache.rs
use std::cell::RefCell;
use std::rc::Rc;

pub async fn remember_review(cache: Rc<RefCell<Vec<Review>>>, review: Review) {
    // Rc and RefCell are not safe to share across multi-threaded async tasks.
    cache.borrow_mut().push(review);
    send_audit_event().await;
}

Review Notes

What to review

Good Code

The good version uses Arc and an async-aware lock, making the shared cache suitable for task boundaries that may move between worker threads.

Bad Code

The bad version uses Rc<RefCell<_>>, then awaits after mutating shared state. That design breaks down when the future must be Send or when borrowing spans grow.

Takeaways

  • Rust async review should check which values cross await points and task boundaries.