Skip to content

transaction statements out of order #2805

@pythoneer

Description

@pythoneer

Bug Description

Not really sure what exactly the bug is but i am seeing strange behavior that makes it look like sql statements are not executed in the correct order. I have a reproduction here ( https://github.com/pythoneer/sqlx_test ) , but it is not really minimal. It uses axum and some strange wrk stuff to trigger it, because that is where i originally encountered that behavior, not sure if it could be further reduced or if it has something to do with how axum operates specifically.

I am just trying to do this in a handler

https://github.com/pythoneer/sqlx_test/blob/c220fda7c5f60fc0ef22f7ba64f3436fac7063e6/src/main2.rs#L41-L59

async fn test(State(pool): State<PgPool>) -> Result<String, (StatusCode, String)> {
    sleep(Duration::from_millis(2)).await;

    let mut transaction = pool.begin().await.map_err(internal_error)?;
    
    // -----------------------8<--------- this is optional ---------------->8----------
    transaction
        .execute("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;")
        .await
        .map_err(|err| panic!("Failed to set transaction isolation level: {:#?}", err))?;

    let data: String = sqlx::query_scalar("select 'hello world from pg'")
        .fetch_one(&pool)
        .await
        .map_err(internal_error)?;
    // -----------------------8<--------- this is optional ---------------->8----------

    transaction.commit().await.map_err(internal_error)?;

    Ok(data)
}

The SET TRANSACTION... and the select 'hello .. can also be removed it will already trigger the problem with just

let mut transaction = pool.begin().await.map_err(internal_error)?;
let transaction.commit().await.map_err(internal_error)?;

but it helps demonstrating the problem.

by running

DATABASE_URL="<your_url>" cargo run --bin binary2

and

./parallel_run.sh

to hit the endpoint we can sporadically see

2023-10-07T20:07:04.706970Z  WARN sqlx::postgres::notice: there is already a transaction in progress
2023-10-07T20:07:08.272585Z  WARN sqlx::postgres::notice: there is no transaction in progress

which i can't really explain. The only way i can think of is if the statements send to the database are not in order? Normally we would see BEGIN; COMMIT; pairs send parallel in each connection, right? But the warnings make me assume that sometime BEGIN; BEGIN; COMMIT; or BEGIN; COMMIT; COMMIT; happens.

With the additional SET TRANSACTION ... and select 'hello .. we can also see panics that i create with

.map_err(|err| panic!("Failed to set transaction isolation level: {:#?}", err))?;

that shows

        code: "25001",
        message: "SET TRANSACTION ISOLATION LEVEL must be called before any query",

and the same problem here, i can only explain this (just playing around in psql) if the select 'hello .. is executed before SET TRANSACTION ....

sqlx.mp4

Also the values (like the sleep and all the wrk parameters and connection pool size) might depend on the specific machine idk, i tuned them to be working the best on my system. I think this can change from system to system. I think it worked the best when the endpoint delivered around 2500 req/s. The reason why i am doing the "funny" stuff in parallel_run.sh is because i noticed that this is somehow triggered specifically in the beginning or the end of a wrk run, not really sure why and what is happening in detail. Maybe wrk "just" kills connection in the middle and axum reacts strange to killed connections while a handler is running idk. But i would say regardless of what axum is doing i don't expect any of the observed things to happen. You can trigger this without parallel_run.sh but you might need to wait and potentially start and stop the wrk command manually fast consecutively. That is basically what parallel_run.sh is doing.

Minimal Reproduction

https://github.com/pythoneer/sqlx_test

needs wrk installed for parallel_run.sh.

DATABASE_URL="<your_url>" cargo run --bin binary2

and

./parallel_run.sh

Info

  • SQLx version: 0.7.2
  • SQLx features enabled:
    "postgres",
    "runtime-tokio-rustls",
    "macros", "migrate",
    "chrono", "json", "uuid",
  • Database server and version: PostgreSQL 15.4 on x86_64-pc-linux-musl, compiled by gcc (Alpine 12.2.1_git20220924-r10) 12.2.1 20220924, 64-bit
  • Operating system: arch linux (x86_64 Linux 6.5.5-arch1-1)
  • rustc --version: rustc 1.72.0 (5680fa18f 2023-08-23)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions