How to send message? (Actix/Actix-web)

Hello.
I'm having trouble sending messages using actors address.
how to fix it?

Code:

//My actor
pub struct DataHub{}

impl Actor for DataHub
{
    type Context = Context<Self>;
    fn started(&mut self, _ctx: &mut Context<Self>) {  }
    fn stopped(&mut self, _ctx: &mut Context<Self>) { }
}

impl Handler<MyMsg> for DataHub
{
    type Result = Result<String, Error>;

    fn handle(&mut self, msg: MyMsg, _: &mut Self::Context) -> Self::Result
    {
     //..any code
    }
}

// I create a my actor
let dh_addr = DataHub::create(move |ctx: &mut Context<DataHub>| { 
//..any code
});

let web_address_cloned = web::Data::new( Mutex::new(dh_addr));

async 
fn index(dh_address: web::Data<Mutex<Addr<DataHub>>>, req: HttpRequest) -> HttpResponse
{
   println!("{:?}", req);

   // ERROR - cannot compile
   let addr = dh_address.lock().unwrap();
   addr.send(MyMsg::new());

   HttpResponse::Ok().finish()
}

HttpServer::new(move || {
 App::new().app_data(web_address_cloned.clone())
.service(web::resource("/").to(index))
}).bind("127.0.0.1:8080").unwrap().run();

let _ = system.run();

Error:

`(dyn actix_web::ResponseError + 'static)` cannot be sent between threads safely

Can you provide full error message? It's unclear from your code where dyn ResponseError is coming from.

dyn ResponseError is not thread-safe. It should have been declared as dyn ResponseError + Send, which allows it to be used on another thread. Sometimes it's an omission that can be fixed easily by adding + Send to types, but sometimes it's intentional and the function using it wants to prevent you from using it. So more context is needed to see what's going on.

It also matters whether you're using .await after locking the Mutex. That's a dangerous combination — mutex must be unlocked before yielding to await points. Otherwise it will stay locked even when the function isn't executing.

Full error msg:

error[E0277]: `(dyn actix_web::ResponseError + 'static)` cannot be sent between threads safely
   --> src/main.rs:395:14
    |
395 |         addr.send(MyMsg::new());
    |              ^^^^ `(dyn actix_web::ResponseError + 'static)` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `(dyn actix_web::ResponseError + 'static)`
    = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn actix_web::ResponseError + 'static)>`
    = note: required because it appears within the type `std::boxed::Box<(dyn actix_web::ResponseError + 'static)>`
    = note: required because it appears within the type `actix_web::Error`
    = note: required because it appears within the type `std::result::Result<std::string::String, actix_web::Error>`

How to fix it?

Oh, I see. It's coming from:

    type Result = Result<String, Error>;

That Error is not your error type, but Actix-web's temporary, non-thread safe type. Don't use it for your errors. Define your own which is some simple type that can be sent across threads. If you have to return an Actix-web response with Actix-web's error somewhere, then convert your error type to Actix's error at the very last moment, so that it won't have to travel between threads.

1 Like