multithreading – Future cannot be sent between threads safely

the relevant code for this question is located here and is also at the bottom of this question.: https://github.com/glitch003/rocket-deno-integration

I’m trying to run some JS inside of Rust using Deno. It works great for synchronous code but I want to use async.

I’m seeing the error “future created by async block is not Send” and “future cannot be sent between threads safely”.

How do I implement Send for the future? Or can I wrap the JSRuntime into some kind of memory safe struct like a Mutex to fix this error?

Removing the “await” from this line makes it compile, but then the JS code isn’t fully run, because nobody is waiting for it to finish: https://github.com/glitch003/rocket-deno-integration/blob/ main/src/functions/mod.rs#L60

Full compilation log is below:

➜  rocketplusdeno git:(main) cargo build                                                               
   Compiling rocketplusdeno v0.1.0 (/Users/chris/Documents/WorkStuff/LIT/testing-and-throwaway/rocketplusdeno)
error: future cannot be sent between threads safely
  --> src/main.rs:17:1
   |
17 | #[post("/")]
   | ^^^^^^^^^^^^ future created by async block is not `Send`
   |
   = help: within `impl std::future::Future<Output = Outcome<rocket::Response<'_>, Status, rocket::Data<'_>>>`, the trait `std::marker::Send` is not implemented for `NonNull<Isolate>`
note: future is not `Send` as this value is used across an await
  --> src/functions/mod.rs:60:37
   |
33 |     let mut js_runtime = JsRuntime::new(RuntimeOptions {
   |         -------------- has type `JsRuntime` which is not `Send`
...
60 |     js_runtime.run_event_loop(false).await;
   |                                     ^^^^^^ await occurs here, with `mut js_runtime` maybe used later
...
65 | }
   | - `mut js_runtime` is later dropped here
   = note: required for the cast to the object type `dyn std::future::Future<Output = Outcome<rocket::Response<'__r>, Status, rocket::Data<'__r>>> + std::marker::Send`
   = note: this error originates in the attribute macro `post` (in Nightly builds, run with -Z macro-backtrace for more info)

error: future cannot be sent between threads safely
  --> src/main.rs:17:1
   |
17 | #[post("/")]
   | ^^^^^^^^^^^^ future created by async block is not `Send`
   |
   = help: the trait `std::marker::Send` is not implemented for `(dyn for<'r> Fn(&'r mut OpState) -> Result<(), anyhow::Error> + 'static)`
note: future is not `Send` as this value is used across an await
  --> src/functions/mod.rs:60:37
   |
23 |     let ext = Extension::builder()
   |         --- has type `Extension` which is not `Send`
...
60 |     js_runtime.run_event_loop(false).await;
   |                                     ^^^^^^ await occurs here, with `ext` maybe used later
...
65 | }
   | - `ext` is later dropped here
   = note: required for the cast to the object type `dyn std::future::Future<Output = Outcome<rocket::Response<'__r>, Status, rocket::Data<'__r>>> + std::marker::Send`
   = note: this error originates in the attribute macro `post` (in Nightly builds, run with -Z macro-backtrace for more info)

error: future cannot be sent between threads safely
  --> src/main.rs:17:1
   |
17 | #[post("/")]
   | ^^^^^^^^^^^^ future created by async block is not `Send`
   |
   = help: the trait `std::marker::Send` is not implemented for `(dyn Fn(OpDecl) -> OpDecl + 'static)`
note: future is not `Send` as this value is used across an await
  --> src/functions/mod.rs:60:37
   |
23 |     let ext = Extension::builder()
   |         --- has type `Extension` which is not `Send`
...
60 |     js_runtime.run_event_loop(false).await;
   |                                     ^^^^^^ await occurs here, with `ext` maybe used later
...
65 | }
   | - `ext` is later dropped here
   = note: required for the cast to the object type `dyn std::future::Future<Output = Outcome<rocket::Response<'__r>, Status, rocket::Data<'__r>>> + std::marker::Send`
   = note: this error originates in the attribute macro `post` (in Nightly builds, run with -Z macro-backtrace for more info)

error: future cannot be sent between threads safely
  --> src/main.rs:17:1
   |
17 | #[post("/")]
   | ^^^^^^^^^^^^ future created by async block is not `Send`
   |
   = help: the trait `std::marker::Send` is not implemented for `(dyn for<'r, 's, 't0> Fn(&'r mut OpState, &'s mut std::task::Context<'t0>) -> bool + 'static)`
note: future is not `Send` as this value is used across an await
  --> src/functions/mod.rs:60:37
   |
23 |     let ext = Extension::builder()
   |         --- has type `Extension` which is not `Send`
...
60 |     js_runtime.run_event_loop(false).await;
   |                                     ^^^^^^ await occurs here, with `ext` maybe used later
...
65 | }
   | - `ext` is later dropped here
   = note: required for the cast to the object type `dyn std::future::Future<Output = Outcome<rocket::Response<'__r>, Status, rocket::Data<'__r>>> + std::marker::Send`
   = note: this error originates in the attribute macro `post` (in Nightly builds, run with -Z macro-backtrace for more info)

error: future cannot be sent between threads safely
  --> src/main.rs:17:1
   |
17 | #[post("/")]
   | ^^^^^^^^^^^^ future created by async block is not `Send`
   |
   = help: within `JsRuntimeInspector`, the trait `std::marker::Send` is not implemented for `Rc<RefCell<UniquePtr<V8Inspector>>>`
note: future is not `Send` as this value is used across an await
  --> src/functions/mod.rs:60:37
   |
33 |     let mut js_runtime = JsRuntime::new(RuntimeOptions {
   |         -------------- has type `JsRuntime` which is not `Send`
...
60 |     js_runtime.run_event_loop(false).await;
   |                                     ^^^^^^ await occurs here, with `mut js_runtime` maybe used later
...
65 | }
   | - `mut js_runtime` is later dropped here
   = note: required for the cast to the object type `dyn std::future::Future<Output = Outcome<rocket::Response<'__r>, Status, rocket::Data<'__r>>> + std::marker::Send`
   = note: this error originates in the attribute macro `post` (in Nightly builds, run with -Z macro-backtrace for more info)

error: future cannot be sent between threads safely
  --> src/main.rs:17:1
   |
17 | #[post("/")]
   | ^^^^^^^^^^^^ future created by async block is not `Send`
   |
   = help: within `JsRuntimeInspector`, the trait `std::marker::Send` is not implemented for `*const [u8; 0]`
note: future is not `Send` as this value is used across an await
  --> src/functions/mod.rs:60:37
   |
33 |     let mut js_runtime = JsRuntime::new(RuntimeOptions {
   |         -------------- has type `JsRuntime` which is not `Send`
...
60 |     js_runtime.run_event_loop(false).await;
   |                                     ^^^^^^ await occurs here, with `mut js_runtime` maybe used later
...
65 | }
   | - `mut js_runtime` is later dropped here
   = note: required for the cast to the object type `dyn std::future::Future<Output = Outcome<rocket::Response<'__r>, Status, rocket::Data<'__r>>> + std::marker::Send`
   = note: this error originates in the attribute macro `post` (in Nightly builds, run with -Z macro-backtrace for more info)

error: future cannot be sent between threads safely
  --> src/main.rs:17:1
   |
17 | #[post("/")]
   | ^^^^^^^^^^^^ future created by async block is not `Send`
   |
   = help: the trait `std::marker::Send` is not implemented for `(dyn std::any::Any + 'static)`
note: future is not `Send` as this value is used across an await
  --> src/functions/mod.rs:60:37
   |
33 |     let mut js_runtime = JsRuntime::new(RuntimeOptions {
   |         -------------- has type `JsRuntime` which is not `Send`
...
60 |     js_runtime.run_event_loop(false).await;
   |                                     ^^^^^^ await occurs here, with `mut js_runtime` maybe used later
...
65 | }
   | - `mut js_runtime` is later dropped here
   = note: required for the cast to the object type `dyn std::future::Future<Output = Outcome<rocket::Response<'__r>, Status, rocket::Data<'__r>>> + std::marker::Send`
   = note: this error originates in the attribute macro `post` (in Nightly builds, run with -Z macro-backtrace for more info)

error: future cannot be sent between threads safely
  --> src/main.rs:17:1
   |
17 | #[post("/")]
   | ^^^^^^^^^^^^ future created by async block is not `Send`
   |
   = help: the trait `std::marker::Send` is not implemented for `(dyn Fn() -> Result<std::string::String, anyhow::Error> + 'static)`
note: future is not `Send` as this value is used across an await
  --> src/functions/mod.rs:60:37
   |
23 |     let ext = Extension::builder()
   |         --- has type `Extension` which is not `Send`
...
60 |     js_runtime.run_event_loop(false).await;
   |                                     ^^^^^^ await occurs here, with `ext` maybe used later
...
65 | }
   | - `ext` is later dropped here
   = note: required for the cast to the object type `dyn std::future::Future<Output = Outcome<rocket::Response<'__r>, Status, rocket::Data<'__r>>> + std::marker::Send`
   = note: this error originates in the attribute macro `post` (in Nightly builds, run with -Z macro-backtrace for more info)

error: future cannot be sent between threads safely
  --> src/main.rs:17:1
   |
17 | #[post("/")]
   | ^^^^^^^^^^^^ future created by async block is not `Send`
   |
   = help: the trait `std::marker::Sync` is not implemented for `(dyn V8InspectorClientImpl + 'static)`
note: future is not `Send` as this value is used across an await
  --> src/functions/mod.rs:60:37
   |
33 |     let mut js_runtime = JsRuntime::new(RuntimeOptions {
   |         -------------- has type `JsRuntime` which is not `Send`
...
60 |     js_runtime.run_event_loop(false).await;
   |                                     ^^^^^^ await occurs here, with `mut js_runtime` maybe used later
...
65 | }
   | - `mut js_runtime` is later dropped here
   = note: required for the cast to the object type `dyn std::future::Future<Output = Outcome<rocket::Response<'__r>, Status, rocket::Data<'__r>>> + std::marker::Send`
   = note: this error originates in the attribute macro `post` (in Nightly builds, run with -Z macro-backtrace for more info)

error: future cannot be sent between threads safely
  --> src/main.rs:17:1
   |
17 | #[post("/")]
   | ^^^^^^^^^^^^ future created by async block is not `Send`
   |
   = help: within `deno_core::inspector::InspectorSession`, the trait `std::marker::Send` is not implemented for `NonNull<V8InspectorSession>`
note: future is not `Send` as this value is used across an await
  --> src/functions/mod.rs:60:37
   |
33 |     let mut js_runtime = JsRuntime::new(RuntimeOptions {
   |         -------------- has type `JsRuntime` which is not `Send`
...
60 |     js_runtime.run_event_loop(false).await;
   |                                     ^^^^^^ await occurs here, with `mut js_runtime` maybe used later
...
65 | }
   | - `mut js_runtime` is later dropped here
   = note: required for the cast to the object type `dyn std::future::Future<Output = Outcome<rocket::Response<'__r>, Status, rocket::Data<'__r>>> + std::marker::Send`
   = note: this error originates in the attribute macro `post` (in Nightly builds, run with -Z macro-backtrace for more info)

error: future cannot be sent between threads safely
  --> src/main.rs:17:1
   |
17 | #[post("/")]
   | ^^^^^^^^^^^^ future created by async block is not `Send`
   |
   = help: the trait `std::marker::Sync` is not implemented for `(dyn ChannelImpl + 'static)`
note: future is not `Send` as this value is used across an await
  --> src/functions/mod.rs:60:37
   |
33 |     let mut js_runtime = JsRuntime::new(RuntimeOptions {
   |         -------------- has type `JsRuntime` which is not `Send`
...
60 |     js_runtime.run_event_loop(false).await;
   |                                     ^^^^^^ await occurs here, with `mut js_runtime` maybe used later
...
65 | }
   | - `mut js_runtime` is later dropped here
   = note: required for the cast to the object type `dyn std::future::Future<Output = Outcome<rocket::Response<'__r>, Status, rocket::Data<'__r>>> + std::marker::Send`
   = note: this error originates in the attribute macro `post` (in Nightly builds, run with -Z macro-backtrace for more info)

error: could not compile `rocketplusdeno` due to 11 previous errors

Minimal reproducible example is available in the github repo but if for some reason you want to see it here in the question, it’s below.

Cargo.toml:


   
[package]
name = "rocketplusdeno"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = "1.0.57"
chrono = "0.4.19"
deno_core = "0.133.0"
ureq = "2.4.0"
rocket = { version = "0.5.0-rc.1", features = ["json"] }
rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", branch = "master" }
tokio = "1.18.2"

src/main.rs

#![allow(unused_variables)]

#[macro_use]
extern crate rocket;

use rocket::http::Method;
use rocket::http::Status;
use rocket::response::status;
use rocket::serde::json::{json, Value};
use rocket_cors::{AllowedOrigins, CorsOptions};

pub mod functions;

/*
curl --request POST http://localhost:8000/
*/
#[get("/")]
async fn execute_js_function() -> status::Custom<Value> {
    let resp = functions::execute_js().await;
    match resp {
        Ok(result) => return status::Custom(Status::Ok, json!({"result": true, "error": ""})),
        Err(err) => {
            return status::Custom(
                Status::BadRequest,
                json!({"message": "Execution error", "errorCode": "execution_error"}),
            );
        }
    }
}

#[launch]
fn rocket() -> _ {
    let cors = CorsOptions::default()
        .allowed_origins(AllowedOrigins::all())
        .allowed_methods(
            vec![Method::Get, Method::Post, Method::Patch]
                .into_iter()
                .map(From::from)
                .collect(),
        )
        .allow_credentials(true)
        .to_cors()
        .expect("CORS failed to build");

    rocket::build()
        .mount("/", routes![execute_js_function])
        .attach(cors)
}

src/functions/mod.rs

use anyhow::Result;
use deno_core::op;
use deno_core::Extension;
use deno_core::JsRuntime;
use deno_core::RuntimeOptions;
use std::convert::TryFrom;
use ureq;

// fn to do an http get
#[op]
fn op_http_get(url: String) -> Result<String, deno_core::error::AnyError> {
    println!("http_get({})", url);

    let body = ureq::get(&url).call()?.into_string()?;
    println!("got body in rust {}", body);

    Ok(body)
}

pub async fn execute_js() -> Result<()> {
    println!("JS code execution started at {}", chrono::Local::now());

    // Build a deno_core::Extension providing custom ops
    let ext = Extension::builder()
        .ops(vec![
            // An op for getting an HTTP url
            // The op-layer automatically deserializes inputs
            // and serializes the returned Result & value
            op_http_get::decl(),
        ])
        .build();

    // Initialize a runtime instance
    let mut js_runtime = JsRuntime::new(RuntimeOptions {
        extensions: vec![ext],
        ..Default::default()
    });

    let code_to_run = r#"
      const console = {
        log: function (value) {
          Deno.core.print(value.toString() + "n");
        },
      };
      
      const go = async () => {
        const resp = Deno.core.opSync(
          "op_http_get",
          "https://ipfs.litgateway.com/ipfs/QmNiDrDnTiSo4y78qKwaZboq8KfT9Y3CRrnM7pfUmG1EFq"
        );
        console.log("resp: " + resp);
      };
      
      go();
    "#;

    js_runtime
        .execute_script("serverless_function.js", &code_to_run)
        .unwrap();

    //   js_runtime.run_event_loop(false).await;

    println!("JS code execution finished at {}", chrono::Local::now());

    Ok(())
}

Leave a Comment