play.api.db.Database.withTransaction has a problem when a JDBC connection dies mid-transaction:
it reports java.sql.SQLException: Connection is closed, and not the error that actually killed it.
The real cause never reaches the caller, and it never reaches the application logs either.
Both overloads are affected: the one taking an isolation level, and the one without.
The transaction itself is handled correctly, and every test here checks that nothing was committed: the server rolls it back as soon as the connection goes away, whichever end of the socket failed. What is lost is only the diagnosis, and it disappears precisely when a database starts misbehaving, in other words, at the very moment where a clear error message would be most valuable.
Reproduced with Play 3.0.11, MariaDB 11.4 and the MariaDB Connector/J 3.5.10.
Requires a Docker-compatible runtime (the test starts a MariaDB container through Testcontainers).
sbt testOutput at the time of issue report:
[info] Database.withTransaction
[info] - should commit the inserted rows
[info] - should report the cause, when the server drops the session *** FAILED ***
[info] java.sql.SQLException: Connection is closed was not an instance of java.sql.SQLNonTransientConnectionException
[info] - should report the cause, when the network timeout expires *** FAILED ***
[info] java.sql.SQLException: Connection is closed was not an instance of java.sql.SQLNonTransientConnectionException
[info] Database.withTransaction, with an isolation level
[info] - should commit the inserted rows
[info] - should report the cause, when the server drops the session *** FAILED ***
[info] java.sql.SQLException: Connection is closed was not an instance of java.sql.SQLNonTransientConnectionException
[info] - should report the cause, when the network timeout expires *** FAILED ***
[info] java.sql.SQLException: Connection is closed was not an instance of java.sql.SQLNonTransientConnectionException
[info] Tests: succeeded 2, failed 4, canceled 0, ignored 0, pending 0
The exception the caller should have received is SQLNonTransientConnectionException: (conn=4) Socket error,
in one case, and SQLNonTransientConnectionException: (conn=9) Socket timout error in the other.
The tests assert the behaviour that is expected of withTransaction, not the behaviour it has today,
so a fix turns the whole suite green without a single change to this repository.
All six must pass, since a fix is only complete once both overloads report the cause.
To try one out, publish your Play build locally, then point this project at it:
# in your playframework checkout
sbt publishLocal # the whole build, play-jdbc alone leaves its own dependencies unresolvable
sbt "show Play-JDBC/version" # the version to use below, e.g. 3.1.0-M10-SNAPSHOT on main
# here
sbt -Dplay.version=<that version> test