0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

RustのWebフレームワークgothamでPostgreSQLとRedisにアクセスする(async/await対応版 gotham0.6)

Last updated at Posted at 2021-09-17

目的

以前書いた記事のバージョンアップ版です。
RustのWebフレームワークgothamでPostgreSQLとRedisにアクセスする

以前との違いはasync/awaitに対応して、Gothamのバージョンを0.6にしています。Tokioも1系になっています。

コード

docker-compose

docker-compose.yaml
version: '3.8'
services:
  api:
    image: rust:buster
    working_dir: /apps/api
    environment:
      - CARGO_BUILD_TARGET_DIR=/tmp/target
      - CARGO_TARGET_DIR=/tmp/target
    volumes:
      - ./apps/api:/apps/api
      - rust_target:/tmp/target
      - rust_cache:/usr/local/cargo/registry
    security_opt:
      - seccomp:unconfined
    tty: true
    ports:
      - "7878:7878"
    depends_on:
      - db
      - redis

  db:
    image: postgres:13-buster
    volumes:
      - postgres:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: app

  redis:
    image: redis:6.2-buster
    command: redis-server --appendonly yes
    ports:
      - "6379:6379"
    volumes:
      - redis:/var/lib/redis/data

volumes:
  rust_cache:
  rust_target:
  postgres:
  redis:

Rust

Cargo.toml
[package]
name = "api"
version = "0.1.0"
edition = "2018"

[dependencies]
anyhow = "^1"
bb8-postgres = "^0.7"
bb8-redis = "^0.10"
http = "^0.2"
gotham = "^0.6"
gotham_derive = "^0.6"
mime = "^0.3"
serde = { version = "^1", features = ["derive"] }
tokio = { version = "^1", features = ["macros"] }
main.rs
use gotham::{
    handler::{SimpleHandlerResult},
    helpers::http::response::create_response,
    middleware::state::StateMiddleware,
    pipeline::{single::single_pipeline, single_middleware},
    router::{builder::*, Router},
    state::{FromState, State},
};

#[macro_use]
extern crate gotham_derive;

#[derive(Clone, StateData)]
pub struct ConfigData {
    pub pg: bb8_postgres::bb8::Pool<
        bb8_postgres::PostgresConnectionManager<bb8_postgres::tokio_postgres::NoTls>,
    >,
    pub redis: bb8_redis::bb8::Pool<bb8_redis::RedisConnectionManager>,
}
impl std::panic::RefUnwindSafe for ConfigData {}
impl ConfigData {
    pub async fn new(pg_url: &str, redis_url: &str) -> anyhow::Result<Self> {
        let pg_manager = bb8_postgres::PostgresConnectionManager::new(
            pg_url.parse().unwrap(),
            bb8_postgres::tokio_postgres::NoTls,
        );
        let pg_pool = bb8_postgres::bb8::Pool::builder().build(pg_manager).await?;

        let redis_manager = bb8_redis::RedisConnectionManager::new(redis_url).unwrap();
        let redis_pool = bb8_redis::bb8::Pool::builder()
            .build(redis_manager)
            .await
            .unwrap();

        Ok(Self {
            pg: pg_pool,
            redis: redis_pool,
        })
    }
}

pub async fn say_hello(state: &mut State) -> SimpleHandlerResult {
    let content = {
        let data = ConfigData::borrow_from(&state);
        let mut redis = data.redis.get().await?;
        let pg = data.pg.get().await?;
        let redis_res: String = bb8_redis::redis::cmd("GET")
            .arg("aaa")
            .query_async(&mut *redis)
            .await
            .unwrap_or("".to_string());
        let pg_res: String = pg
            .query("SELECT $1::TEXT", &[&"予定表〜①ハンカクだ3".to_string()])
            .await?
            .get(0)
            .unwrap()
            .get(0);
        format!("{}:{}", redis_res, pg_res)
    };

    let response = create_response(
        &state,
        gotham::hyper::StatusCode::OK,
        mime::TEXT_PLAIN,
        content,
    );

    Ok(response)
}

async fn router(config_data: ConfigData) -> Router {
    let middleware = StateMiddleware::new(config_data);

    let pipeline = single_middleware(middleware);

    let (chain, pipelines) = single_pipeline(pipeline);

    build_router(chain, pipelines, |route| {
        route.get("/").to_async_borrowing(say_hello);
    })
}

#[tokio::main]
async fn main() {
    let pg_url = std::env::var("PG_URL").unwrap();
    let redis_url = std::env::var("REDIS_URL").unwrap();
    let config_data = ConfigData::new(&pg_url, &redis_url).await.unwrap();
    let addr = "0.0.0.0:7878";
    println!("Listening for requests at http://{}", addr);
    let _ = gotham::init_server(addr, router(config_data).await).await;
}
PG_URL=postgresql://user:pass@db/app REDIS_URL=redis://redis:6379 cargo run

おまけ

コネクションプールはbb8, deadpool, r2d2がありますが、実は最初deadpoolで試していたんですが、redisはうまく来ましたがpostgresqlがランタイムが無いみたいなエラーで出て動きませんでした。本来ならdeadpool-postgresを使うだけでdefaultでランタイムが指定されるはずなんですが、うまくいきません。r2d2は非同期をサポートしてなかったのでbb8に行きつきました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?