Confused by error about future not being Send

I'm trying to run the following code involving tungstenite and a async_std channel. It works fine when I remove the line below as I commented, but I get an error that's confusing to me when that line is left in.

Could anyone suggest what I should change to get it working?

Basically I want to "catch" any network errors from run_once, send the error on the channel, and then call run_once again.

use futures::StreamExt;

async fn run_once(ch:async_std::sync::Sender<String>) -> Result<(), Box<dyn std::error::Error>> {
    let (mut ws, _) = async_tungstenite::async_std::connect_async("wss://foo").await?;
    loop {
        let msg = ws.next().await.ok_or("got none() for ws.next()")??.into_text()?;
        ch.send(msg).await;
        async_std::task::sleep(std::time::Duration::from_millis(1000)).await;
    }
}

async fn run(ch:async_std::sync::Sender<String>) {
    while let Err(_) = run_once(ch.clone()).await {
        // I don't understand why, but
        // commenting the following line gets rid of the problem.
        ch.send("error".into()).await;
    }
}

fn main() {
    let (ch_in, _ch_out) = async_std::sync::channel(1000);
    async_std::task::block_on(async {
        async_std::task::spawn(run(ch_in));
        // actual code does more things here
    });
}
error: future cannot be sent between threads safely
  --> src/main.rs:23:9
   |
23 |         async_std::task::spawn(run(ch_in));
   |         ^^^^^^^^^^^^^^^^^^^^^^ future returned by `run` is not `Send`
   |
  ::: /home/me/.cargo/registry/src/github.com-1ecc6299db9ec823/async-std-1.6.2/src/task/spawn.rs:28:29
   |
28 |     F: Future<Output = T> + Send + 'static,
   |                             ---- required by this bound in `async_std::task::spawn`
   |
   = help: the trait `std::marker::Send` is not implemented for `dyn std::error::Error`
note: future is not `Send` as this value is used across an await
  --> src/main.rs:16:9
   |
13 |     while let Err(_) = run_once(ch.clone()).await {
   |                        -------------------------- has type `std::result::Result<(), std::boxed::Box<dyn std::error::Error>>` which is not `Send`
...
16 |         ch.send("error".into()).await;
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `run_once(ch.clone()).await` maybe used later
17 |     }
   |     - `run_once(ch.clone()).await` is later dropped here

error: aborting due to previous error

Change Box<dyn std::error::Error> to Box<dyn std::error::Error + Send + Sync>.

1 Like