Actix Rust deadpool_ postgres: соединения с БД не освобождены - PullRequest
0 голосов
/ 10 июля 2020

У меня есть сервер Actix-web, который подключается к Postgres БД.

Я заметил, что после 1000 запросов использование моей Postgres БД ОЗУ увеличилось .

Когда я останавливаю actix-web, ОЗУ, удерживаемое db, очищается. Это заставляет меня думать, что мой код не освобождает соединение.

Я не могу найти пример фактически освобождаемых соединений. Похоже, это заключено в чужом коде.

Вот мой:

async fn hellow_world(a : f32, b : f32, pool: &Pool) -> Result<Value, PoolError> {
    let client: Client = pool.get().await?;
    let sql = format!("select \"json\" from public.table_a WHERE a={} and b={}", a, b);
    let stmt = client.prepare(&sql).await?;
    let row = client.query_one(&stmt, &[]).await?;
    let result : Value = row.get(0);
    Ok(result)
}

#[derive(Deserialize)]
pub struct MyRequest {
   a: f32,
   b: f32
}

#[get("/hello")]
async fn sv_hellow_world(info: web::Query<MyRequest>, db_pool: web::Data<Pool>) -> Result<HttpResponse, Error> {
    let response : Value = hellow_world(info.a, info.b, &db_pool).await?;
    Ok(HttpResponse::Ok().json(response))
}

#[actix_rt::main]
async fn main() -> std::io::Result<()> {
    dotenv().ok();
    let config = Config::from_env().unwrap();
    let pool = config.pg.create_pool(tokio_postgres::NoTls).unwrap();

    env_logger::from_env(Env::default().default_filter_or("info")).init();

    let server = HttpServer::new(move || App::new().wrap(Logger::default()).wrap(Logger::new("%a %{User-Agent}i")).data(pool.clone()).service(sv_hellow_world))
        .bind("0.0.0.0:3000")?
        .run();
    server.await
}

1 Ответ

1 голос
/ 12 июля 2020

На основании дальнейшего тестирования @Werner определил, что код накапливал подготовленные операторы на стороне сервера.

Неясно, можно ли закрыть эти операторы с помощью этой библиотеки.

Чтобы избежать этой проблемы, можно использовать два подхода:

  1. Используйте один общий подготовленный оператор
  2. Используйте форму прямого запроса вместо подготовленного оператора

Я принципиально рекомендую первый подход, так как он более эффективен и защищает от SQL инъекции. Он должен выглядеть примерно так:

async fn hellow_world(a : f32, b : f32, pool: &Pool) -> Result<Value, PoolError> {
    let client: Client = pool.get().await?;
    let stmt = client.prepare("select \"json\" from public.table_a WHERE a=$1::numeric and b=$2::numeric").await?;
    let row = client.query_one(&stmt, &[&a, &b]).await?;
    let result : Value = row.get(0);
    Ok(result)
}

Используя этот код, для каждого соединения пула должен быть создан только один подготовленный оператор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...