【问题标题】:Using redis-rs with actix-web将 redis-rs 与 actix-web 一起使用
【发布时间】:2020-11-08 08:15:52
【问题描述】:

我正在尝试将 redis 作为 web::Data 上下文添加到我的 actix-web rust 应用程序:

extern crate redis;

// std imports
use std::net::SocketAddr;
// external imports
use actix_web::{App, HttpServer};
use redis::Client

#[actix_rt::main]
async fn main() -> std::io::Result<()> {
    // connect to redis
    let redis_con = Client::open("redis://127.0.0.1:6379")
        .unwrap()
        .get_connection()
        .unwrap();

    HttpServer::new(move || App::new().data(redis_con).service(api::get_healthz))
        .bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8080)?
        .run()
        .await
}

我收到以下错误: the trait bound 'redis::Connection: std::clone::Clone' is not satisfied in '[closure@src/main.rs:48:21: 48:81 redis_con:redis::Connection]'

我已经尝试将其包装为Arc&lt;redis::Connection&gt;,这对于未实现Syncredis::Connection 子模块深处的某些类型也不起作用。

在这种情况下我没有看到 Rust 的概念吗? 这是我第一个真正的 Rust 项目之一,所以我可能忽略了一些东西。

【问题讨论】:

    标签: redis rust rust-actix actix-web


    【解决方案1】:

    此答案是 Actix 解决问题的最小示例。不过,可能有更短的方法可以实现您想要的。

    首先你需要导入actix crate:

    [package]
    name = "test-actix-redis"
    version = "0.1.0"
    authors = ["Njuguna Mureithi <email@gmail.com>"]
    edition = "2018"
    
    # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
    
    [dependencies]
    actix-web = "2.0"
    actix-rt = "1.0"
    redis = "0.15"
    actix = "0.10.0-alpha.3"
    

    然后定义你的演员:

    use actix_web::{web, App, HttpResponse, HttpServer, Responder};
    use redis::{Client, aio::MultiplexedConnection};
    use actix::prelude::*;
    
    struct RedisActor {
        conn: MultiplexedConnection,
    }
    
    impl RedisActor {
        pub async fn new(redis_url: &'static str) -> Self {
            let client = Client::open(redis_url).unwrap();// not recommended
            let (conn, call) = client.get_multiplexed_async_connection().await.unwrap();
            actix_rt::spawn(call);
            RedisActor { conn }
        }
    }
    
    #[derive(Message, Debug)]
    #[rtype(result = "Result<Option<String>, redis::RedisError>")]
    struct InfoCommand;
    
    
    
    impl Handler<InfoCommand> for RedisActor {
        type Result = ResponseFuture<Result<Option<String>, redis::RedisError>>;
    
        fn handle(&mut self, _msg: InfoCommand, _: &mut Self::Context) -> Self::Result {
            let mut con = self.conn.clone();
            let cmd = redis::cmd("INFO");
            let fut = async move {
                cmd
                    .query_async(&mut con)
                    .await
            };
            Box::pin(fut)
        }
    }
    
    
    impl Actor for RedisActor {
        type Context = Context<Self>;
    }
    
    async fn info(redis: web::Data<Addr<RedisActor>>) -> impl Responder {
        let res = redis.send(InfoCommand).await.unwrap().unwrap().unwrap();
        HttpResponse::Ok().body(res)
    }
    
    
    
    
    #[actix_rt::main]
    async fn main() -> std::io::Result<()> {
        let actor = RedisActor::new("redis://127.0.0.1:6379").await;
        let addr = actor.start();
        HttpServer::new(move || {
            App::new()
                .data(addr.clone())
                .route("/", web::get().to(info))
        })
        .bind("127.0.0.1:8088")?
        .run()
        .await
    }
    

    现在运行您的项目:

    cargo run
    

    转到http://localhost:8088/ 应该会给你你的redis信息作为一个字符串。

    【讨论】:

    • 非常感谢。我知道这似乎是 actix 的 Actor 系统的完美用例。
    • 重要的一点是,始终检查tokioredis crate 和actix crate 中使用的版本。他们需要在同一个版本上。否则,您将收到关于未在 tokio 运行时中运行的错误。
    猜你喜欢
    • 2016-07-09
    • 2015-08-17
    • 2015-05-16
    • 1970-01-01
    • 1970-01-01
    • 2019-12-13
    • 1970-01-01
    • 2021-01-25
    • 2018-11-22
    相关资源
    最近更新 更多