< 返回版块

招宝进财 发表于 2023-12-22 16:24


main:
...

let wrap_pool = Arc::new(RwLock::new(pool));

    // Compose the routes
    let app = Router::new()
        .route("/insert", post(insert_new_round))
        // Add middleware to all routes
        .layer(
            ServiceBuilder::new()
                .layer(HandleErrorLayer::new(|error: BoxError| async move {
                    if error.is::<tower::timeout::error::Elapsed>() {
                        Ok(StatusCode::REQUEST_TIMEOUT)
                    } else {
                        Err((
                            StatusCode::INTERNAL_SERVER_ERROR,
                            format!("Unhandled internal error: {error}"),
                        ))
                    }
                }))
                .timeout(Duration::from_secs(10))
                .layer(TraceLayer::new_for_http())
                .into_inner(),
        )
        .with_state(wrap_pool);

...

async fn insert_new_round(State(db): State<Arc<RwLock<Pool<Sqlite>>>>, Json(round): Json<Round>) -> impl IntoResponse {

    let db_lock = db.write().unwrap();
    let pool_ref = &*db_lock;
    match insert_round_to_db(pool_ref, &round).await {
        Ok(_) => return (StatusCode::OK, Json( "Success".to_string())),
        Err(e) => return (StatusCode::OK, Json(e.to_string())),
    }
  //  return (StatusCode::OK, Json( "Success".to_string()));
}


async fn insert_round_to_db(pool: &SqlitePool, round: &Round) -> Result<i64, String> 

route("/insert", post(insert_new_round))

出现编译错误

--> src/main.rs:70:32
    |
70  |         .route("/insert", post(insert_new_round))
    |                           ---- ^^^^^^^^^^^^^^^^ the trait `Handler<_, _>` is not implemented for fn item `fn(State<Arc<std::sync::RwLock<sqlx::Pool<Sqlite>>>>, axum::Json<Round>) -> impl std::future::Future<Output = impl IntoResponse> {insert_new_round}`
    |                           |
    |                           required by a bound introduced by this call
    |
    = help: the following other types implement trait `Handler<T, S>`:
              <axum::handler::Layered<L, H, T, S> as Handler<T, S>>
              <MethodRouter<S> as Handler<(), S>>
note: required by a bound in `post`

但是奇怪的是如果insert_new_round 函数修改成

async fn insert_new_round(State(db): State<Arc<RwLock<Pool<Sqlite>>>>, Json(round): Json<Round>) -> impl IntoResponse {

    let db_lock = db.write().unwrap();
    let pool_ref = &*db_lock;
 //   match insert_round_to_db(pool_ref, &round).await {
 //       Ok(_) => return (StatusCode::OK, Json( "Success".to_string())),
 //       Err(e) => return (StatusCode::OK, Json(e.to_string())),
 //   }
   return (StatusCode::OK, Json( "Success".to_string()));
}

就没有编译错误了. 问题就出在 函数中是否调用了 insert_round_to_db(pool_ref, &round).await .

搜索了很久没有搞明白为什么会出现这个错误.

评论区

写评论
作者 招宝进财 2023-12-24 12:16

多谢多谢. 基本搞明白了.

--
👇
Bai-Jinlin: 你的锁是用的标准库的RwLock,RwLockWriteGuard是!Send的,!Send只要跨越了await点会导致你这个future不是Send的,所以不满足trait bound。 非形式的来说是因为你这个future在这个线程lock,但是这个future可能会在await点被tokio转移到其他线程这时在非lock线程unlock是不被定义的行为,所以这个Guard是!Send。改成tokio的锁就好了。

--
👇
招宝进财: 可否解释的更详细一些?

  1. 这里用Arc包裹了一层, Arc是Send呀.
  2. RwLock换成tokio的tokio::sync::Mutex 是不就可以解决问题了.

--
👇
bestgopher: lock跨await导致函数非Send

Bai-Jinlin 2023-12-22 19:08

你的锁是用的标准库的RwLock,RwLockWriteGuard是!Send的,!Send只要跨越了await点会导致你这个future不是Send的,所以不满足trait bound。 非形式的来说是因为你这个future在这个线程lock,但是这个future可能会在await点被tokio转移到其他线程这时在非lock线程unlock是不被定义的行为,所以这个Guard是!Send。改成tokio的锁就好了。

--
👇
招宝进财: 可否解释的更详细一些?

  1. 这里用Arc包裹了一层, Arc是Send呀.
  2. RwLock换成tokio的tokio::sync::Mutex 是不就可以解决问题了.

--
👇
bestgopher: lock跨await导致函数非Send

作者 招宝进财 2023-12-22 17:59

可否解释的更详细一些?

  1. 这里用Arc包裹了一层, Arc是Send呀.
  2. RwLock换成tokio的tokio::sync::Mutex 是不就可以解决问题了.

--
👇
bestgopher: lock跨await导致函数非Send

bestgopher 2023-12-22 17:30

lock跨await导致函数非Send

1 共 4 条评论, 1 页