rust 错误:future不能在线程之间安全地发送

mfpqipee  于 2023-08-05  发布在  其他
关注(0)|答案(1)|浏览(146)

我正在使用Actix_web在Rust中构建API服务。我有一个API处理函数register_business,负责向数据库添加新业务。
my API处理程序函数

#[post("/businesses/")]
async fn add_business(payload: web::Json<BusinessPayload>,pool: Connection) ->Result<HttpResponse,Error>{
     //error thrown here web::block
    let reg_business = web::block(move || {
        let conn = pool.get().unwrap();
        register_business(payload.into_inner(), &conn)
    })
    .await
    .unwrap()
    .await
    .map_err(|_| actix_web::error::ErrorInternalServerError("Internal Server Error"))?;

    Ok(HttpResponse::Ok().json(reg_business))
}

字符串
register_business函数

pub async fn register_business(payload: BusinessPayload, conn: &PgConnection) -> Result<Business, DbError> {
    let images_paths = upload_images(payload.images).await.unwrap();

            let reg_business = NewBusiness {
                uuid: nanoid!(),
                images: images_paths,

               //assigning other payload values here
            };

            let res_registration = diesel::insert_into(businesses)
                .values(&reg_business)
                .get_result(conn)?;

            Ok(res_registration)
}


最后我的upload_image,它接受一个base64编码字符串数组,向cloudinary API发出请求并存储图像路径。

pub async fn upload_images(payload: Vec<String>) -> Result<Vec<String>, Error> {
    let client = Client::default();
    let mut uploaded_images = Vec::new();
     //TODO: move key to env var
    let api_key = String::from("api-key-here");
    let authorization_header = format!("Bearer {}", api_key);

    for image_data in payload {
        let response = client
            .post("https://api.cloudinary.com/v1_1/deye3gicq/image/upload")
            .insert_header(("Authorization", authorization_header.clone()))
            .send_body(image_data)
            .await
            .unwrap()
            .json::<Value>()
            .await
            .unwrap();

        if let Some(image_url) = response.get("imageUrl").and_then(Value::as_str) {
            uploaded_images.push(image_url.to_string());
            println!("{:?}", image_url);
        }
    }

    Ok(uploaded_images)
}


我正在使用这个项目来学习Rust,无法确定这里可能有什么问题。如有任何帮助,我们将不胜感激。
我试过检查Rust手册,但无法修复此错误。对于上下文,这是完整的编译器诊断错误。

error: future cannot be sent between threads safely
   --> src/routes/handlers.rs:32:24
    |
32  |     let reg_business = web::block(move || {
    |                        ^^^^^^^^^^ future returned by `register_business` is not `Send`
    |
    = help: within `diesel::PgConnection`, the trait `Sync` is not implemented for `NonNull<pq_sys::pg_conn>`
note: future is not `Send` as this value is used across an await
   --> src/utils/helpers.rs:19:53
    |
18  | pub async fn register_business(payload: BusinessPayload, conn: &PgConnection) -> Result<Business, DbError> {
    |                                                          ---- has type `&diesel::PgConnection` which is not `Send`
19  |     let images_paths = upload_images(payload.images).await.unwrap();
    |                                                     ^^^^^^ await occurs here, with `conn` maybe used later
...
44  | }
    | - `conn` is later dropped here
note: required by a bound in `block`
   --> /Users/cooper/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-web-4.3.1/src/web.rs:215:8
    |
215 |     R: Send + 'static,
    |        ^^^^ required by this bound in `block`

nzk0hqpo

nzk0hqpo1#

错误是说传入web::block的闭包的返回类型不是Send。这个错误看起来有点复杂,因为实际上是从web::block返回Future。这几乎总是错误的。web::block用于执行 * 分块 * 代码,而不是异步代码。
您可以通过仅在实际的diesel交互(阻塞代码)上进行阻塞来解决此问题。看看the example diesel integration

pub async fn register_business(payload: BusinessPayload, pool: Connection) -> Result<Business, DbError> {
    let images_paths = upload_images(payload.images).await.unwrap();

    web::block(move || {
        let reg_business = NewBusiness {
            uuid: nanoid!(),
            images: images_paths,
            // ...
        };
        // `pool` is moved into this closure
        let conn = pool.get().expect("couldn't get db connection from pool");
    
        diesel::insert_into(businesses)
            .values(&reg_business)
            .get_result(conn)
    })
    .await
    .expect("failed to run blocking code")
}

#[post("/businesses/")]
async fn add_business(payload: web::Json<BusinessPayload>, pool: Connection) -> Result<HttpResponse,Error>{
    let reg_business = register_business(payload.into_inner(), pool)
        .await
        .map_err(|_| actix_web::error::ErrorInternalServerError("Internal Server Error"))?;

    Ok(HttpResponse::Ok().json(reg_business))
}

字符串

相关问题