【问题标题】:Share state between actix-web server and async closure在 actix-web 服务器和异步关闭之间共享状态
【发布时间】:2022-10-23 16:19:16
【问题描述】:

我想定期获取数据(使用异步reqwest),然后使用actix-web 作为服务器在http 端点提供这些数据。 (我有一个具有固定格式的数据源,我想由需要不同格式的服务读取,所以我需要转换数据。) 我尝试将 actix 概念与 Rust 书中的线程共享状态示例结合起来,但我不明白错误或如何解决它。 这是尽可能缩小的代码:

use actix_web::{get, http, web, App, HttpResponse, HttpServer, Responder};
use std::sync::{Arc, Mutex};
use tokio::time::{sleep, Duration};

struct AppState {
    status: String,
}

#[get("/")]
async fn index(data: web::Data<Mutex<AppState>>) -> impl Responder {
    let state = data.lock().unwrap();
    HttpResponse::Ok()
        .insert_header(http::header::ContentType::plaintext())
        .body(state.status.to_owned())
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let status_string = get_state().await.unwrap();
    let app_data = Arc::new(Mutex::new(web::Data::new(AppState {
        status: status_string,
    })));

    let app_data1 = Arc::clone(&app_data);
    actix_web::rt::spawn(async move {
        loop {
            println!("I get executed every 2-ish seconds!");
            sleep(Duration::from_millis(2000)).await;

            let res = get_state().await;
            let mut app_data = app_data1.lock().unwrap();
            // this line is not accepted by the compiler
            *app_data.status = res.unwrap();
        }
    });

    let app_data2 = Arc::clone(&app_data);
    HttpServer::new(move || App::new().app_data(app_data2).service(index))
        .bind(("127.0.0.1", 9090))?
        .run()
        .await
}

async fn get_state() -> Result<String, Box<dyn std::error::Error>> {
    let client = reqwest::Client::new().get("http://ipecho.net/plain".to_string());
    let status = client.send().await?.text().await?;
    println!("got status: {status}");

    Ok(status)
}

但我收到以下错误:

error[E0308]: mismatched types
  --> src/main.rs:33:32
   |
33 |             *app_data.status = res.unwrap();
   |             ----------------   ^^^^^^^^^^^^ expected `str`, found struct `String`
   |             |
   |             expected due to the type of this binding

error[E0277]: the size for values of type `str` cannot be known at compilation time
  --> src/main.rs:33:13
   |
33 |             *app_data.status = res.unwrap();
   |             ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `str`
   = note: the left-hand-side of an assignment must have a statically known size

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.

为什么我突然收到str?是否有一个简单的解决方法或者我的方法来解决这个错误? Edit: 也许删除 * 是正确的方法,因为彼得霍尔建议,但这给了我以下错误:

error[E0594]: cannot assign to data in an `Arc`
  --> src/main.rs:33:13
   |
33 |             app_data.status = res.unwrap();
   |             ^^^^^^^^^^^^^^^ cannot assign
   |
   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc<AppState>`

error[E0507]: cannot move out of `app_data2`, a captured variable in an `Fn` closure
  --> src/main.rs:38:49
   |
37 |     let app_data2 = Arc::clone(&app_data);
   |         --------- captured outer variable
38 |     HttpServer::new(move || App::new().app_data(app_data2).service(index))
   |                     -------                     ^^^^^^^^^ move occurs because `app_data2` has type `Arc<std::sync::Mutex<Data<AppState>>>`, which does not implement the `Copy` trait
   |                     |
   |                     captured by this `Fn` closure

Some errors have detailed explanations: E0507, E0594.
For more information about an error, try `rustc --explain E0507`.

我的Cargo.toml 依赖项:

[dependencies]
actix-web = "4.2.1"
reqwest = "0.11.12"
tokio = "1.21.2"

【问题讨论】:

  • 我认为您只需要丢失*app_data.status = res.unwrap();

标签: rust smart-pointers dereference rust-tokio actix-web


【解决方案1】:

这一行:

*app_data.status = res.unwrap();

相当于这个:

*(app_data.status) = res.unwrap();

StringDeref 实现将 str 作为关联的 Target 类型,这就是您在错误消息中看到它的原因。

您可能打算做的是:

(*app_data).status = res.unwrap();

但是这种尊重是自动发生的,所以你可以写:

app_data.status = res.unwrap();

【讨论】:

  • 我相信你在理论上是对的,你可能已经回答了以问号结尾的句子:)。但它不起作用,并给我其他错误。 “无法分配给Arc 中的数据”,对于有问题的行,以及“无法移出app_data2Fn 闭包中的捕获变量”(第 37 行)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-27
  • 2023-03-12
  • 1970-01-01
相关资源
最近更新 更多