Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kotlin Suspend @Transactional Function Issue #2949

Closed
rmondejar opened this issue May 17, 2024 · 2 comments · Fixed by #2954
Closed

Kotlin Suspend @Transactional Function Issue #2949

rmondejar opened this issue May 17, 2024 · 2 comments · Fixed by #2954

Comments

@rmondejar
Copy link

rmondejar commented May 17, 2024

Expected Behavior

When an exception that extends kotlin.Throwable is thrown in a Kotlin suspend function, the transaction should be rolled back and the connection should be properly released back to the connection pool.

This would allow other transactions to use the connection and prevent potential resource leaks or deadlocks. The code block that is not being reached should be executed, ensuring that the transaction is either committed if no exceptions occurred, or rolled back if an exception was thrown.

In a nutshell, in the io.micronaut.transaction.async.AsyncUsingSyncTransactionOperations.withTransaction function, this part of the code should be reached:

result.whenComplete((o, throwable) -> {
    if (throwable == null) {
        synchronousTransactionManager.commit(status);
        newResult.complete(o);
    } else {
        try {
            synchronousTransactionManager.rollback(status);
        } catch (Exception e) {
            // Ignore rethrow
        }
        newResult.completeExceptionally(throwable);
    }
});

Actual Behaviour

Micronaut Data fails to evict an active connection when a @transactional suspend function throws an exception extending Throwable, resulting in a new connection being opened for each subsequent request

Steps To Reproduce

  1. Environment Setup
  • IDE: IntelliJ IDEA 2023.3.6
  • Languages: Kotlin 1.9.23, Java 21
  • Frameworks: Micronaut 4.4.2, Gradle
  • Libraries: Kotlin coroutines 1.8.0
  1. Configuration
  1. Run
  • Execute the test that reproduces the issue with the following command:
    ./gradlew -i test --rerun-tasks --tests "com.example.DemoTest.hikariIssue"
  1. See Error
    "Unexpected Exception: io.micronaut.http.client.exceptions.ReadTimeoutException: Read Timeout"
  • Observe that an exception that extends kotlin.Throwable in a suspend function causes the transaction to be rolled back, but the connection is not released back to the pool

Environment Information

  • Operating System: macOS 14.4.1
  • JDK: Temurin 21.0.1

Example Application

https://github.com/uberall/mn-kotlin-transactional-issue

Version

4.4.2

@dstepanov
Copy link
Contributor

Your project is not accessible. Please integrate test-resources for your tests so no docker commands are needed.

@rmondejar
Copy link
Author

rmondejar commented May 17, 2024

Your project is not accessible. Please integrate test-resources for your tests so no docker commands are needed.

Sorry, I thought it was public already, that's fixed now 👍

Regarding integrating test-resources is a great tip, we added it as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants