Passing Actix Web Payload to function - rust

I'd like to factor out some payload handling logic from my route handler. I'm not sure how to handle the type appropriately. Specifically, I want to mark the payload as Send safe, but the compiler complains that I cannot send payload across threads. How can I guarantee this Payload will only be handled by the relevant worker thread?
Let's say I have a route
#[post("/upload")]
pub async fn upload(mut body: Payload) -> Result<HttpResponse> {
Handler {}.handle_payload(body).await?;
}
This is one of many possible handlers, and so I define a simple trait with an implementation.
#[async_trait::async_trait]
pub trait Handle {
async fn handle_payload(&self, s: impl Stream + Send) -> Result<()>;
}
pub struct Handler {}
#[async_trait::async_trait]
impl Handle for Handler {
async fn handle_payload(&self, s: impl Stream + Send) -> Result<()> {
Ok(())
}
}
This results in the compiler shouting that I can't send Payload between threads. How can I factor an async payload processor out of the route?
| MyHandler {}.handle_payload(body).await?;
| -------------- ^^^^ `Rc<RefCell<actix_http::h1::payload::Inner>>` cannot be sent between threads safely
| |
| required by a bound introduced by this call
|
= help: within `actix_web::web::Payload`, the trait `std::marker::Send` is not implemented for `Rc<RefCell<actix_http::h1::payload::Inner>>`
= note: required because it appears within the type `actix_http::h1::payload::Payload`
= note: required because it appears within the type `actix_web::dev::Payload`
= note: required because it appears within the type `actix_web::web::Payload`
and
| MyHandler {}.handle_payload(body).await?;
| -------------- ^^^^ `(dyn futures_util::Stream<Item = Result<actix_web::web::Bytes, PayloadError>> + 'static)` cannot be sent between threads safely
| |
| required by a bound introduced by this call
|
= help: the trait `std::marker::Send` is not implemented for `(dyn futures_util::Stream<Item = Result<actix_web::web::Bytes, PayloadError>> + 'static)`
= note: required for `Unique<(dyn futures_util::Stream<Item = Result<actix_web::web::Bytes, PayloadError>> + 'static)>` to implement `std::marker::Send`
= note: required because it appears within the type `Box<(dyn futures_util::Stream<Item = Result<actix_web::web::Bytes, PayloadError>> + 'static)>`
= note: required because it appears within the type `Pin<Box<(dyn futures_util::Stream<Item = Result<actix_web::web::Bytes, PayloadError>> + 'static)>>`
= note: required because it appears within the type `actix_web::dev::Payload`
= note: required because it appears within the type `actix_web::web::Payload`

Actix web does not require its handlers to be thread-safe. The webserver uses multiple threads, but once a request has been assigned to a thread, it doesn't move. As such, many actix-specific types (like Payload) are not thread-safe since they don't need to be.
However, async_trait assumes the asynchronous function should be thread-safe by default. You can relax this constraint by passing ?Send in your annotations:
#[async_trait::async_trait(?Send)]
pub trait Handle {
async fn handle_payload(&self, s: impl Stream + Send) -> Result<()>;
}
pub struct Handler {}
#[async_trait::async_trait(?Send)]
impl Handle for Handler {
async fn handle_payload(&self, s: impl Stream + Send) -> Result<()> {
Ok(())
}
}
See Non-threadsafe futures from the async-trait documentation.

Related

What is the difference between `future` and `async move { future }`?

I'm wondering why changing the code from using a Future directly to using it in an async move block makes a difference. Passing it to tokio::spawn directly yields an error:
use std::error::Error;
use tokio::sync::{mpsc::{self, Receiver}, oneshot::Sender};
struct Msg {
resp: Sender<Vec<u8>>,
}
async fn client_thread(
mut rx: Receiver<Msg>,
) -> Result<(), Box<dyn Error>> {
while let Some(msg) = rx.recv().await {
msg.resp
.send(vec![]) // return some data
.unwrap();
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let (_tx, rx) = mpsc::channel(5);
tokio::spawn(client_thread(rx));
Ok(())
}
error[E0277]: `(dyn std::error::Error + 'static)` cannot be sent between threads safely
--> src/main.rs:23:5
|
23 | tokio::spawn(client_thread(rx)); // <--- Difference is here
| ^^^^^^^^^^^^ `(dyn std::error::Error + 'static)` cannot be sent between threads safely
|
= help: the trait `Send` is not implemented for `(dyn std::error::Error + 'static)`
= note: required because of the requirements on the impl of `Send` for `Unique<(dyn std::error::Error + 'static)>`
= note: required because it appears within the type `Box<(dyn std::error::Error + 'static)>`
= note: required because it appears within the type `Result<(), Box<(dyn std::error::Error + 'static)>>`
note: required by a bound in `tokio::spawn`
--> /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.21.0/src/task/spawn.rs:128:20
|
128 | T::Output: Send + 'static,
| ^^^^ required by this bound in `tokio::spawn`
But changing it to an async block makes it compile:
tokio::spawn(async move { client_thread(rx) });
The return type of client_thread is exactly the same as the main function, however, which runs with Tokio without any problems. Moreover, the error type from reqwest implements Send.
Wrapping the Future in an async {} block as you've done makes it compile but doesn't actually run the Future. You need to .await it:
use futures::executor::block_on; // 0.3.12
async fn f(s: &str) {
println!("ran {}", s);
}
fn main() {
block_on(f("first"));
block_on(async { f("second") }); // this doesn't print
block_on(async { f("third").await });
}
ran first
ran third
Since the future is not ran, it doesn't end up affecting the traits for the async {} block and thus can can satisfy the Send constraint. You'll have the same issue again with .await.
In your case, all you need to do is ensure that the future implements Send so it can be ran with tokio::spawn. The fix is to dictate that the Error trait being returned implements Send:
async fn client_thread(
mut rx: Receiver<ClientMsg>,
) -> Result<(), Box<dyn Error + Send>> {
// ... ^^^^^^
}

Why usage of async block in then makes my Stream Unpin?

I'm new to Rust and I'm sorry if I'm using terms incorrect. Maybe my choice of words for question is incorrect.
I was playing with streams and I needed to have some delay between stream elements. So I wrote this:
use futures::stream;
use futures::StreamExt;
use tokio::time;
#[tokio::main]
async fn main() {
let mut stream = stream::iter(0..1000).then(|x| async move {
time::delay_for(std::time::Duration::from_millis(500)).await;
x + 1
});
while let Some(x) = stream.next().await {
println!("{:?}", x)
}
}
I get a lot of compilation errors, but the most important errors are connected with pinning. Here they are:
error[E0277]: `std::future::from_generator::GenFuture<[static generator#src/main.rs:7:64: 10:6 x:_ _]>` cannot be unpinned
--> src/main.rs:11:32
|
11 | while let Some(x) = stream.next().await {
| ^^^^ within `futures_util::stream::stream::then::_::__Then<'_, futures_util::stream::iter::Iter<std::ops::Range<{integer}>>, impl core::future::future::Future, [closure#src/main.rs:7:49: 10:6]>`, the trait `std::marker::Unpin` is not implemented for `std::future::from_generator::GenFuture<[static generator#src/main.rs:7:64: 10:6 x:_ _]>`
|
= note: required because it appears within the type `impl core::future::future::Future`
= note: required because it appears within the type `std::option::Option<impl core::future::future::Future>`
= note: required because it appears within the type `futures_util::stream::stream::then::_::__Then<'_, futures_util::stream::iter::Iter<std::ops::Range<{integer}>>, impl core::future::future::Future, [closure#src/main.rs:7:49: 10:6]>`
= note: required because of the requirements on the impl of `std::marker::Unpin` for `futures_util::stream::stream::then::Then<futures_util::stream::iter::Iter<std::ops::Range<{integer}>>, impl core::future::future::Future, [closure#src/main.rs:7:49: 10:6]>`
error[E0277]: `std::future::from_generator::GenFuture<[static generator#src/main.rs:7:64: 10:6 x:_ _]>` cannot be unpinned
--> src/main.rs:11:25
|
11 | while let Some(x) = stream.next().await {
| ^^^^^^^^^^^^^^^^^^^ within `futures_util::stream::stream::then::_::__Then<'_, futures_util::stream::iter::Iter<std::ops::Range<{integer}>>, impl core::future::future::Future, [closure#src/main.rs:7:49: 10:6]>`, the trait `std::marker::Unpin` is not implemented for `std::future::from_generator::GenFuture<[static generator#src/main.rs:7:64: 10:6 x:_ _]>`
|
= note: required because it appears within the type `impl core::future::future::Future`
= note: required because it appears within the type `std::option::Option<impl core::future::future::Future>`
= note: required because it appears within the type `futures_util::stream::stream::then::_::__Then<'_, futures_util::stream::iter::Iter<std::ops::Range<{integer}>>, impl core::future::future::Future, [closure#src/main.rs:7:49: 10:6]>`
= note: required because of the requirements on the impl of `std::marker::Unpin` for `futures_util::stream::stream::then::Then<futures_util::stream::iter::Iter<std::ops::Range<{integer}>>, impl core::future::future::Future, [closure#src/main.rs:7:49: 10:6]>`
= note: required because of the requirements on the impl of `core::future::future::Future` for `futures_util::stream::stream::next::Next<'_, futures_util::stream::stream::then::Then<futures_util::stream::iter::Iter<std::ops::Range<{integer}>>, impl core::future::future::Future, [closure#src/main.rs:7:49: 10:6]>>`
If I change my code to this:
use futures::stream;
use futures::StreamExt;
use tokio::time;
#[tokio::main]
async fn main() {
let mut stream = stream::iter(0..1000).then(|x| {
futures::future::ready(x + 1)
});
while let Some(x) = stream.next().await {
println!("{:?}", x)
}
}
Or to this:
use futures::stream;
use futures::StreamExt;
use tokio::time;
#[tokio::main]
async fn main() {
stream::iter(0..1000)
.then(|x| async move {
time::delay_for(std::time::Duration::from_millis(500)).await;
x + 1
})
.for_each(|x| async move { println!("{:?}", x) })
.await;
}
It compiles.
I assume it has something to do with pinning and simultaneous usage of then combinator and while, but I can't wrap my head around it.
I think that the issue boils down to the fact that async blocks are not Unpin. It can be proven with this code:
fn check_unpin<F: Unpin>(_: F) { }
fn main() {
check_unpin(async {});
}
that fails with the rather cryptic message:
error[E0277]: `std::future::from_generator::GenFuture<[static generator#src/main.rs:4:23: 4:25 _]>` cannot be unpinned
--> src/main.rs:4:5
|
1 | fn check_unpin<F: Unpin>(_: F) { }
| ----- required by this bound in `check_unpin`
...
4 | check_unpin(async {});
| ^^^^^^^^^^^ within `impl std::future::Future`, the trait `std::marker::Unpin` is not implemented for `std::future::from_generator::GenFuture<[static generator#src/main.rs:4:23: 4:25 _]>`
|
= note: required because it appears within the type `impl std::future::Future`
I reckon that GenFuture is the internal type that converts an async block into a impl Future.
Now back to your issue, the combinator then() returns an Unpin value if both the stream and the Future returned by the closure are Unpin (it is not totally clear in the documentation, but I've inferred that from the source code). The stream::iter is Unpin, but when you write |x| async move { x + 1} you are returning an async block that is not Unpin, thus your error.
If you use futures::future::ready(x + 1) it works simply because that Future implements Unpin.
If you use StreamExt::for_each it works because it does not require Self to be Unpin. It is not Unpin itself, but it does not matter because you are sending it up to tokio::main that pins everything internally before polling.
If you want your original code to work you just have to manually pin your stream (playground):
use futures::stream;
use futures::StreamExt;
use tokio::time;
use pin_utils::pin_mut;
#[tokio::main]
async fn main() {
let stream = stream::iter(0..1000).then(|x| async move {
time::delay_for(std::time::Duration::from_millis(500)).await;
x + 1
});
pin_mut!(stream); //<---- here, pinned!
while let Some(x) = stream.next().await {
println!("{:?}", x)
}
}

Avoiding `Sync` for shared static variables

I have the following definitions:
struct MyCustomFactory;
trait Factory {
fn new<'a>(entity: &'a str) -> Arc<dyn Display + 'a>
where
Self: Sized;
}
impl Factory for MyCustomFactory {
fn new<'a>(entity: &'a str) -> Arc<dyn Display + 'a>
where
Self: Sized,
{
Arc::new(entity)
}
}
Higher level problem:
I'm trying to create a global static (and immutable) map of strings to structs which implement the Factory trait. The goal is that for any value member of the map, I can treat it like a Factory, call new against it, and in turn will get something back that (in this case) implements the Display trait.
I have the following:
static ITEMS: Lazy<BTreeMap<&'static str, Arc<dyn Factory>>> =
Lazy::new(|| {
let mut map = BTreeMap::new();
let value = Arc::new(MyCustomFactory) as Arc<dyn Factory>;
map.insert("foo", value);
map
});
The compiler complains with:
77 | / static ITEMS: Lazy<BTreeMap<&'static str, Arc<dyn Factory>>> =
78 | | Lazy::new(|| {
79 | | let map = BTreeMap::new();
80 | | let value = Arc::new(MyCustomFactory) as Arc<dyn Factory>;
... |
88 | | });
| |_______^ `(dyn Factory + 'static)` cannot be shared between threads safely
|
= help: the trait `std::marker::Sync` is not implemented for `(dyn Factory + 'static)`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<(dyn Factory + 'static)>`
= note: required because of the requirements on the impl of `std::marker::Send` for `alloc::collections::btree::node::Root<&'static str, std::sync::Arc<(dyn Factory + 'static)>>`
= note: required because it appears within the type `std::collections::BTreeMap<&'static str, std::sync::Arc<(dyn Factory + 'static)>>`
= note: required because of the requirements on the impl of `std::marker::Sync` for `once_cell::imp::OnceCell<std::collections::BTreeMap<&'static str, std::sync::Arc<(dyn Factory + 'static)>>>`
= note: required because it appears within the type `once_cell::sync::OnceCell<std::collections::BTreeMap<&'static str, std::sync::Arc<(dyn Factory + 'static)>>>`
= note: required because of the requirements on the impl of `std::marker::Sync` for `once_cell::sync::Lazy<std::collections::BTreeMap<&'static str, std::sync::Arc<(dyn Factory + 'static)>>>`
= note: shared static variables must have a type that implements `Sync`
Things I have tried:
Implement Sync against the trait: Declaring the trait to have trait Factory : Sync, (meaning all items which implement the trait, must implement Sync) and/or defining:
|
66 | unsafe impl Sync for dyn Factory {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
Wrapping Arc<dyn Factory>: I've tried using Mutex / RefCell / OnceCell and others, all resulting in the same error. It seems like there should be a way to treat the underlying MyCustomFactory as a Singleton that can be locked around. It's fine (and expected) that's there's only once instance of this struct globally.
You were close with adding Sync. If you look closely you'll see that the error then recommends adding Send:
= help: the trait `std::marker::Send` is not implemented for `(dyn Factory + 'static)`
Add both Send and Sync and it compiles. You can do:
trait Factory: Send + Sync {
...
}
Or, my preference, require them specifically in the static map, since that's where they're needed:
static ITEMS: Lazy<BTreeMap<&'static str, Arc<dyn Factory + Send + Sync>>> =
Lazy::new(|| {
let mut map = BTreeMap::new();
let value = Arc::new(MyCustomFactory) as Arc<dyn Factory + Send + Sync>;
map.insert("foo", value);
map
});
You could also reduce duplication by letting it infer the second Arc:
let value = Arc::new(MyCustomFactory) as Arc<_>;

Rust: impl trait cannot be shared between threads safely

I have a struct RabbitMQBackend which implements a trait Backend like:
pub trait Backend {
// Start consuming message from the queue.
fn pull(&self, sender: &Sender<String>);
}
pub struct RabbitMQBackend {
// Some fields ...
}
impl Backend for RabbitMQBackend {
fn pull(&self, sender: &Sender<String>) {do something...}
}
I am creating an instance of this struct like:
let rmq_backend = RabbitMQBackend::new("amqp://user:password#localhost:5672/", "testqueue2");
let mut consumer = ThreadConsumer::new();
consumer.consume(&rmq_backend);
where ThreadConsumer is:
pub struct ThreadConsumer {
pub sender: Sender<String>,
pub receiver: Receiver<String>,
}
impl Consumer for ThreadConsumer {
fn new() -> Self {
let (sender, receiver) = bounded(3);
ThreadConsumer {
sender: sender,
receiver: receiver,
}
}
fn consume(&mut self, backend: &impl Backend) {
let consumer = thread::spawn(move || {
backend.pull(&self.sender);
});
}
}
The problem is I am trying to call the backend.pull function from inside a separate thread, but I am getting this error:
error[E0277]: `impl Backend` cannot be shared between threads safely
--> src/consumer/thread_consumer/thread_consumer.rs:23:24
|
23 | let consumer = thread::spawn(move || {
| ^^^^^^^^^^^^^ `impl Backend` cannot be shared between threads safely
|
= help: the trait `std::marker::Sync` is not implemented for `impl Backend`
help: consider further restricting this bound with `+ std::marker::Sync`
--> src/consumer/thread_consumer/thread_consumer.rs:20:37
|
20 | fn consume(&mut self, backend: &impl Backend) {
| ^^^^^^^^^^^^
= note: required because of the requirements on the impl of `std::marker::Send` for `&impl Backend`
= note: required because it appears within the type `[closure#src/consumer/thread_consumer/thread_consumer.rs:23:38: 25:10 backend:&impl Backend, self:&mut consumer::thread_consumer::thread_consumer::ThreadConsumer]
Note 1: I tried implementing the Send and Senc trait for the Backend trait and RabbitMQBackend struct like:
pub trait Backend: Send + Sync {
// Start consuming message from the queue.
fn pull(&self, sender: &Sender<String>);
}
pub struct RabbitMQBackend {
// Some fields ...
}
unsafe impl Send for RabbitMQBackend {}
unsafe impl Sync for RabbitMQBackend {}
then passed the backend function arg like
fn consume(&mut self, backend: &impl Backend + Send + Sync) {...}
but it raised the following error
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the types are compatible:
How can I resolve this issue?
The native Rust threads are not scoped. This means once the thread is spawned it will live its life independent from its creator (as far as the Rust compiler is concerned anyway). So if you want to move a reference into a thread, that reference needs to live forever (aka 'static) as, as far as the compiler is concerned, the creator thread could die immediately and the child never.
So I see two solutions there:
don't do that, use something like Arc (and probably a mutex or rwlock depending on the thread safety of the backend) or somesuch for your backend, such that your backend has "multiple owners" via the Arc, this way you obviate the ref' issue
use scoped threads

How do I resolve the compilation error "Unpin not implemented for GenFuture" resulting from adapting a stream using a combinator?

I'm unable to work out how to resolve the compilation error resulting from adapting a stream using a combinator.
The following Rust Playground demonstrates a fairly minimal example:
use futures::prelude::*;
use futures::StreamExt;
#[derive(Debug)]
pub enum Input {
A,
B(i32),
C(u16),
}
#[derive(Debug)]
enum Output {
Int(i32),
Short(u16),
}
pub struct StreamMaker;
impl StreamMaker {
/// make a stream with a series of inputs
pub fn create(self) -> impl Stream<Item = Input> {
stream::iter(vec![Input::A, Input::C(1u16), Input::B(2)])
}
}
/// consume the creator, and make output messages for a subset
pub fn adapt_stream(creator: StreamMaker) -> impl Stream<Item = Output> {
let mut upstream = creator.create();
upstream.filter_map(|message| async move {
match message {
Input::A => None,
Input::B(v) => Some(Output::Int(v)),
Input::C(v) => Some(Output::Short(v)),
}
})
}
#[tokio::main]
async fn main() -> Result<(), ()> {
let creator = StreamMaker {};
let mut stream = adapt_stream(creator);
while let Some(message) = stream.next().await {
println!("message: {:?}", message)
}
Ok(())
}
Compilation fails with:
error[E0277]: the trait bound `std::future::GenFuture<[static generator#src/main.rs:29:46: 35:6 message:Input {}]>: std::marker::Unpin` is not satisfied in `impl core::future::future::Future`
--> src/main.rs:43:38
|
43 | while let Some(message) = stream.next().await {
| ^^^^ within `impl core::future::future::Future`, the trait `std::marker::Unpin` is not implemented for `std::future::GenFuture<[static generator#src/main.rs:29:46: 35:6 message:Input {}]>`
|
= help: the following implementations were found:
<std::future::GenFuture<T> as std::marker::Unpin>
= note: required because it appears within the type `impl core::future::future::Future`
= note: required because of the requirements on the impl of `std::marker::Unpin` for `futures_util::stream::stream::filter_map::FilterMap<impl futures_core::stream::Stream, impl core::future::future::Future, [closure#src/main.rs:29:25: 35:6]>`
= note: required because it appears within the type `impl futures_core::stream::Stream`
error[E0277]: the trait bound `std::future::GenFuture<[static generator#src/main.rs:29:46: 35:6 message:Input {}]>: std::marker::Unpin` is not satisfied in `impl core::future::future::Future`
--> src/main.rs:43:31
|
43 | while let Some(message) = stream.next().await {
| ^^^^^^^^^^^^^^^^^^^ within `impl core::future::future::Future`, the trait `std::marker::Unpin` is not implemented for `std::future::GenFuture<[static generator#src/main.rs:29:46: 35:6 message:Input {}]>`
|
= help: the following implementations were found:
<std::future::GenFuture<T> as std::marker::Unpin>
= note: required because it appears within the type `impl core::future::future::Future`
= note: required because of the requirements on the impl of `std::marker::Unpin` for `futures_util::stream::stream::filter_map::FilterMap<impl futures_core::stream::Stream, impl core::future::future::Future, [closure#src/main.rs:29:25: 35:6]>`
= note: required because it appears within the type `impl futures_core::stream::Stream`
= note: required because of the requirements on the impl of `core::future::future::Future` for `futures_util::stream::stream::next::Next<'_, impl futures_core::stream::Stream>`
I can put a pin_mut!(stream); in the main, but I'd like to be able to push that upstream.
If you do not want the consumer of your stream to have to pin it themselves, you need to return a stream that implements the Unpin trait, meaning that it is safe to move around in memory even after is has been pinned.
pub fn adapt_stream(creator: StreamMaker) -> impl Stream<Item = Output> + Unpin {
// add Unpin trait --^
Adding this, your compiler should complain that the return value doesn't implement Unpin. This is because async move { ... } blocks don't implement Unpin, since they may be self-referential (e.g. contain references to variables they own). The most general way to work around this is to pin the stream to the heap with a Pin<Box<_>>, using the Box::pin constructor:
pub fn adapt_stream(creator: StreamMaker) -> impl Stream<Item = Output> + Unpin {
let mut upstream = creator.create();
Box::pin(upstream.filter_map(|message| async move {
// ^-- pin stream to heap
match message {
Input::A => None,
Input::B(v) => Some(Output::Int(v)),
Input::C(v) => Some(Output::Short(v)),
}
}))
}
Since we're now returning a Pin<Box<_>> pointer to the stream, that pointer can be safely moved around in memory while the inner stream is kept at the same location.
Full playground example

Resources