Skip to content

PgClient. Commit transaction after exception. #1369

Open
@Tiikara

Description

@Tiikara

Questions

I have encountered some strange transaction behaviour. If I execute a query after the transaction starts, create a checkpoint, then this query terminates with an exception (in my case an index constraint error). Then I rollback the checkpoint, and after that when commit transaction the system hangs. At the same time rollback works. In Debug I saw that there is a flag failed in the transaction object. Is this how it should be or am I doing something wrong?

Version

4.4.6

Context

Language

Kotlin

Packages

  • io.vertx:vertx-core
  • io.vertx:vertx-lang-kotlin-coroutines
  • io.vertx:vertx-lang-kotlin
  • io.vertx:vertx-pg-client

Location

Vertx Verticle

Code

@OptIn(DelicateCoroutinesApi::class)
fun <T> launchCoroutineOnEventLoopAsVertxFuture(block: suspend () -> T) : Future<T> {
  val vertx = Vertx.currentContext()

  val promise = Promise.promise<T>()

  GlobalScope.launch(vertx.dispatcher()) {
    try {
      promise.complete(block())
    } catch (ex: Exception) {
      promise.fail(ex)
    }
  }

  return promise.future()
}
suspend fun <T, Error> withSavepoint(sqlConnection: SqlConnection, block: suspend () -> OkOrError<T, Error>): OkOrError<T, Error> {
    sqlConnection
      .query("SAVEPOINT AsyncSqlConnectionPgSavepointWithErrorHandling")
      .execute()
      .await()

    try {
      val result = block()

      if(result.isError) {
        sqlConnection
          .query("ROLLBACK TO SAVEPOINT AsyncSqlConnectionPgSavepointWithErrorHandling")
          .execute()
          .await()
      }

      return result
    }
    catch (e: PgException) {
      sqlConnection
          .query("ROLLBACK TO SAVEPOINT AsyncSqlConnectionPgSavepointWithErrorHandling")
          .execute()
          .await()

      throw e
    }
    finally {
      sqlConnection
          .query("RELEASE SAVEPOINT AsyncSqlConnectionPgSavepointWithErrorHandling")
          .execute()
          .await()
    }
  }
pgPool.withConnection { sqlConnection ->
  launchCoroutineOnEventLoopAsVertxFuture {
    val transaction = sqlConnection.begin().await()

      try {
        val result = 
           try {
              withSavepoint(sqlConnection) {
                 functionWithDatabaseException()
              }
           } catch(e: PgException) {
              ....
             Ok(...)
           }

        if(result.isOk) {
          transaction.commit().await() // here problem
        } else {
          transaction.rollback().await()
        }

        return result
      } catch (e: Exception) {
        transaction.rollback().await()
        throw e
      }
  }
}.await()

After stuck on the line transaction.commit().await(). With a query in PostgreSQL, I can see that the last query from the application to the database is ROLLBACK.

SELECT *
FROM pg_stat_activity
WHERE application_name = 'vertx-pg-client'

PS Everything works fine if I manually make BEGIN/COMMIT requests with SqlConnection instead sqlConnection.begin()/transaction.commit().

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions