zio-jdbc
zio-jdbc copied to clipboard
ZIO failure in `ZConnectionPool.transaction`
I'm getting an InterruptedException
in ZConnectionPool.transaction
. I am unable to mapError
or tapError
on the failure. When I run it unsafe, I get a zio.Exit.Failure
. Nothing I have tried has allowed me to see the cause of the failure, e.g., the stack trace of the InterruptedException
.
I've boiled my problem down to a pretty minimal test case. If I take out the debugging code, which I thought you might find helpful, it comes in well under 50 lines. I am using zio version 2.1.9 and zio-jdbc version 0.1.2
import zio.{ ZIO, ZLayer }
import zio.jdbc.{ ZConnectionPool, ZConnectionPoolConfig, stringToSql }
import zio.test.Assertion.equalTo
import zio.test.{ ZIOSpecDefault, assert }
class Api(val connectionPool: ZConnectionPool) {
val query = stringToSql("SELECT 'foo'").query[String]
val selectOne = connectionPool.transaction(query.selectOne)
val fooZIO: ZIO[Any, Throwable, Option[String]] = for {
_ <- ZIO.debug("before selectOne")
foo <- selectOne.tapError(e => ZIO.debug(s"tapError selectOne $e"))
_ <- ZIO.debug("after selectOne")
} yield foo
}
object ApiSpec extends ZIOSpecDefault {
val connectionPoolConfigLayer = ZLayer.succeed(ZConnectionPoolConfig.default)
val connectionPoolLayer = ZConnectionPool.postgres(
"localhost", 5432, "test", Map("user" -> "test", "password" -> "test")
)
val apiLayer = ZLayer(ZIO.service[ZConnectionPool].map { connectionPool =>
new Api(connectionPool)
})
val layer = connectionPoolConfigLayer >>> connectionPoolLayer >>> apiLayer
zio.Unsafe.unsafe { implicit unsafe =>
val z = zio.Runtime.default.unsafe.run {
for {
_ <- ZIO.debug("before")
z <- ZIO.service[Api].provide(layer).flatMap(_.fooZIO)
.tapError(e => ZIO.debug(s"EEE $e"))
.tapDefect(e => ZIO.debug(s"EEE $e"))
.tapBoth(e => ZIO.debug(s"EEE $e"), e => ZIO.debug(s"EEE $e"))
_ <- ZIO.debug("after")
} yield z
}
println(z)
}
def spec = test("api.fooZIO should be Some(foo)") {
for {
api <- ZIO.service[Api].provide(layer)
_ <- ZIO.debug("before login")
response <- api.fooZIO
_ <- ZIO.debug("after login")
} yield {
assert(response)(equalTo(Some("foo")))
}
}
}
Here is the output when I run sbt test
:
before
before selectOne
Failure(Both(Empty,Both(Empty,Interrupt(Runtime(378775985,1727107547164,zio.jdbc.ZConnectionPool.make.tx(ZConnectionPool.scala:168)),Stack trace for thread "zio-fiber-378775985,2016155100,708221690,403450518":
at zio.jdbc.ZConnectionPool.make.tx(ZConnectionPool.scala:168)
at <empty>.Api.selectOne(ApiSpec.scala:8)
at <empty>.Api.fooZIO(ApiSpec.scala:12)
at <empty>.Api.fooZIO(ApiSpec.scala:14)
at <empty>.ApiSpec.<local ApiSpec$>.z(ApiSpec.scala:35)
at <empty>.ApiSpec.<local ApiSpec$>.z(ApiSpec.scala:36)
at <empty>.ApiSpec.<local ApiSpec$>.z(ApiSpec.scala:37)
at <empty>.ApiSpec.<local ApiSpec$>.z(ApiSpec.scala:40)
at <empty>.ApiSpec.<local ApiSpec$>.z(ApiSpec.scala:41)))))
before login
before selectOne
- api.fooZIO should be Some(foo)
Exception in thread "zio-fiber-59,58,56,51" java.lang.InterruptedException: Interrupted by thread "zio-fiber-59"
at zio.jdbc.ZConnectionPool.make.tx(ZConnectionPool.scala:168)
at <empty>.Api.selectOne(ApiSpec.scala:8)
at <empty>.Api.fooZIO(ApiSpec.scala:12)
at <empty>.Api.fooZIO(ApiSpec.scala:14)
at <empty>.ApiSpec.spec(ApiSpec.scala:53)
at <empty>.ApiSpec.spec(ApiSpec.scala:54)
0 tests passed. 1 tests failed. 0 tests ignored.
- api.fooZIO should be Some(foo)
Exception in thread "zio-fiber-59,58,56,51" java.lang.InterruptedException: Interrupted by thread "zio-fiber-59"
at zio.jdbc.ZConnectionPool.make.tx(ZConnectionPool.scala:168)
at <empty>.Api.selectOne(ApiSpec.scala:8)
at <empty>.Api.fooZIO(ApiSpec.scala:12)
at <empty>.Api.fooZIO(ApiSpec.scala:14)
at <empty>.ApiSpec.spec(ApiSpec.scala:53)
at <empty>.ApiSpec.spec(ApiSpec.scala:54)
Executed in 564 ms
[info] Completed tests
[error] Failed tests:
[error] ApiSpec
[error] (Test / testOnly) sbt.TestsFailedException: Tests unsuccessful
You will note from the output that the error is completely untappable. It's possible that there is something wrong with my zio-jdbc
code and/or Postgres setup, and there is a real error hidden in there somewhere. But I highly doubt it because, inexplicably, I have another test that does nearly the exact same thing, and it passes. And I mean, it passes every time. And this test I shared here fails every time.
The output shows line 168 in ZConnectionPool.scala
. That's from zio-jdbc
version 0.1.2. Poking a bit in the debugger, the error seems to arise from ZConnection.close
.
Whatever is going on, it seems pretty clear that there is a zio-jdbc
bug in here somewhere, because I really should be able to map or tap the error.