с соединениями. Не нравится тем, что засоряет сигнатуру функции.
#[get("api/users")]
pub async fn get_user(user_info: Json<UserInfo>, pool: Data<PgPool>) -> ResultJson<User> {
let result = users_service::get_user(user_info.0, &mut acquire_conn!(pool)).await;
ok_json!(result.map_err(error::ErrorUnprocessableEntity)?)
}
Завести статик, импортировать его и передавать в функцию:
static DB: tokio::sync::OnceCell<PgPool> = tokio::sync::OnceCell::const_new();
// в мейне зовём get_or_init
#[get("api/users")]
pub async fn get_user(user_info: Json<UserInfo>) -> ResultJson<User> {
let result = users_service::get_user(user_info.0, &mut acquire_conn!(DB)).await;
ok_json!(result.map_err(error::ErrorUnprocessableEntity)?)
}
Какие могут быть проблемы, есть ли разница в перфе?
actix_web::web::Data - обёртка над Arc<T>, то есть пул это Arc<PgPool>
во втором случае это будет tokio::sync::OnceCell<PgPool>, то есть UnsafeCell + семафор с одним атомиком.
Почему задался этим: надоело каждый раз писать pool: Data<PgPool> и потом дерефить его.
Насколько лучше актиксовский шаред стейт чем собственный с токийскими oncecell'ами?
С учётом того, что токийский OnceCell возвращает Option, я бы вообще использовал unsafe { DB.get_unchecked() } чтобы вырезать ветку паники, учитывая, что до роутов невозможно добраться, минуя инит пула.
С глобальной переменной ты не сможешь в одном процессе запустить два экземпляра приложения с разными PgPull-ами. Не сможешь в тестах менять значение этого статика на лету. Ну в целом, глобальные переменные - это зло.
В чем проблема передавать коннекшн вместо пулла?
Хм. Тогда не проще атрибутным макросом прокидывать коннекшен в аргументы функции неявно? Под #[post()] навесить #[with_pool] Или вообще брать коннекшен прямо внутри функции. #[with_connection(var_name="conn")] Хотя это уже макросы ради макросов. Точнее макросы ради "не засорять функцию двумя строчками"
коннекшен надо сначала взять.
В чем проблема?
Обсуждают сегодня