/axum-sea-orm-tx

Request-scoped SeaORM transactions for axum

Primary LanguageRustMIT LicenseMIT

TL;DR don't use this

I attempted to port axum-sqlx-tx to sea-orm, but for reasons that are mysterious to me, the middleware is leaking connections and eventually exhausts the pool.

What I did instead is a relatively simple Axum from_fn_with_state style middleware:

async fn run_request_bound_transaction<B>(
  mut request: Request<B>,
  next: Next<B>,
  db: &DatabaseConnection,
) -> Result<Response, DbErr> {
  let extensions_mut = request.extensions_mut();
  let tx = db.begin().await?;
  let tx_arc = Arc::new(tx);

  extensions_mut.insert(ConnectionWrapper::DatabaseTransaction(Arc::downgrade(
    &tx_arc,
  )));
  let response = next.run(request).await;
  let tx = Arc::try_unwrap(tx_arc).map_err(|arc| {
    DbErr::Custom(format!(
      "Cannot finish database transaction because it still has {} strong references",
      Arc::strong_count(&arc)
    ))
  })?;

  if response.status().is_success() {
    tx.commit().await?;
  } else {
    tx.rollback().await?;
  }

  Ok(response)
}

pub async fn request_bound_transaction<B>(
  State(db_conn): State<Arc<DatabaseConnection>>,
  request: Request<B>,
  next: Next<B>,
) -> Response {
  run_request_bound_transaction(request, next, &db_conn)
    .await
    .unwrap_or_else(|err| (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response())
}