Skip to content

Commit

Permalink
Merge pull request #2166 from deusaquilus/catch_close
Browse files Browse the repository at this point in the history
Catch close() exceptions
  • Loading branch information
deusaquilus committed Jun 15, 2021
2 parents e8cde7f + c40b347 commit f4d3979
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 10 deletions.
22 changes: 18 additions & 4 deletions quill-jdbc-zio/src/main/scala/io/getquill/context/ZioJdbc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.typesafe.config.Config
import io.getquill.JdbcContextConfig
import zio.{ Has, Task, ZIO, ZLayer, ZManaged }
import zio.stream.ZStream
import io.getquill.util.LoadConfig
import io.getquill.util.{ ContextLogger, LoadConfig }
import izumi.reflect.Tag

import java.io.Closeable
Expand All @@ -31,7 +31,7 @@ object ZioJdbc {
def fromDataSource(ds: => DataSource with Closeable) =
for {
block <- ZManaged.environment[Blocking]
managedDs <- ZManaged.fromAutoCloseable(Task(ds))
managedDs <- managedBestEffort(Task(ds))
} yield (Has(managedDs) ++ block)
}

Expand All @@ -41,7 +41,7 @@ object ZioJdbc {
fromBlocking <- ZManaged.environment[Has[DataSource with Closeable] with Blocking]
from = fromBlocking.get[DataSource with Closeable]
blocking = fromBlocking.get[Blocking.Service]
r <- ZManaged.fromAutoCloseable(ZIO.effect(from.getConnection).refineToOrDie[SQLException]: ZIO[Any, SQLException, Connection])
r <- managedBestEffort(ZIO.effect(from.getConnection)).refineToOrDie[SQLException]: ZManaged[Any, SQLException, Connection]
} yield Has(r) ++ Has(blocking)
ZLayer.fromManagedMany(managed)
}
Expand All @@ -68,7 +68,7 @@ object ZioJdbc {
for {
block <- ZManaged.environment[Blocking]
conf <- ZManaged.fromEffect(Task(jdbcContextConfig))
ds <- ZManaged.fromAutoCloseable(Task(conf.dataSource: DataSource with Closeable))
ds <- managedBestEffort(Task(conf.dataSource: DataSource with Closeable))
} yield (Has(ds) ++ block)
)
}
Expand Down Expand Up @@ -126,4 +126,18 @@ object ZioJdbc {
env = Has(provision) ++ rest
result <- qzio.provide(env)
} yield result

/**
* This is the same as `ZManaged.fromAutoCloseable` but if the `.close()` fails it will log `"close() of resource failed"`
* and continue instead of immediately throwing an error in the ZIO die-channel. That is because for JDBC purposes,
* a failure on the connection close is usually a recoverable failure. In the cases where it happens it occurs
* as the byproduct of a bad state (e.g. failing to close a transaction before closing the connection or failing to
* release a stale connection) which will eventually cause other operations (i.e. future reads/writes) to fail
* that have not occurred yet.
*/
def managedBestEffort[T <: AutoCloseable](effect: Task[T]) =
ZManaged.make(effect)(resource =>
ZIO.effect(resource.close()).tapError(e => ZIO.effect(logger.underlying.error(s"close() of resource failed", e)).ignore).ignore)

private[getquill] val logger = ContextLogger(ZioJdbc.getClass)
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import scala.reflect.ClassTag
* {{
* val zioConn =
* ZLayer.fromManaged(for {
* ds <- ZManaged.fromAutoCloseable(Task(JdbcContextConfig(LoadConfig("testPostgresDB")).dataSource))
* conn <- ZManaged.fromAutoCloseable(Task(ds.getConnection))
* ds <- ZioJdbc.managedBestEffort(Task(JdbcContextConfig(LoadConfig("testPostgresDB")).dataSource))
* conn <- ZioJdbc.managedBestEffort(Task(ds.getConnection))
* } yield conn)
*
* MyZioContext.run(query[Person]).provideCustomLayer(zioConn)
Expand Down Expand Up @@ -228,8 +228,8 @@ abstract class ZioJdbcContext[Dialect <: SqlIdiom, Naming <: NamingStrategy] ext
ZStream.managed {
for {
conn <- ZManaged.make(Task(conn))(c => Task.unit)
ps <- ZManaged.fromAutoCloseable(Task(prepareStatement(conn)))
rs <- ZManaged.fromAutoCloseable(Task(ps.executeQuery()))
ps <- managedBestEffort(Task(prepareStatement(conn)))
rs <- managedBestEffort(Task(ps.executeQuery()))
} yield (conn, ps, rs)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.getquill.examples

import io.getquill._
import io.getquill.context.ZioJdbc
import io.getquill.util.LoadConfig
import zio.{ App, ExitCode, Task, URIO, ZLayer, ZManaged }
import zio.console.putStrLn
Expand All @@ -14,8 +15,8 @@ object ZioApp extends App {

val zioConn =
ZLayer.fromManaged(for {
ds <- ZManaged.fromAutoCloseable(Task(JdbcContextConfig(LoadConfig("testPostgresDB")).dataSource))
conn <- ZManaged.fromAutoCloseable(Task(ds.getConnection))
ds <- ZioJdbc.managedBestEffort(Task(JdbcContextConfig(LoadConfig("testPostgresDB")).dataSource))
conn <- ZioJdbc.managedBestEffort(Task(ds.getConnection))
} yield conn)

override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = {
Expand Down
29 changes: 29 additions & 0 deletions quill-jdbc-zio/src/test/scala/io/getquill/mock/ZioMockSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,35 @@ class ZioMockSpec extends AnyFreeSpec with MockitoSugar { //with AsyncMockitoSug
order.verifyNoMoreInteractions()
}

"managed connection throwing exception on close is caught internally" in {
val people = List(Person("Joe", 11), Person("Jack", 22))

val ds = mock[MyDataSource]
val conn = mock[Connection]
val stmt = mock[PreparedStatement]
val rs = MockResultSet(people)

when(ds.getConnection) thenReturn conn
when(conn.prepareStatement(any[String])) thenReturn stmt
when(stmt.executeQuery()) thenReturn rs
when(conn.close()) thenThrow (new SQLException("Could not close the connection"))

val ctx = new PostgresZioJdbcContext(Literal)
import ctx._

val results =
ctx.run(query[Person])
.provideConnectionFrom(ds).defaultRun

results must equal(people)

// In test suite verifications come after
val order = inOrder(Seq[AnyRef](conn, stmt, rs): _*)
// connection close bracket
order.verify(conn).close()
order.verifyNoMoreInteractions()
}

"stream is correctly closed when ending conn.setAutoCommit returns error but is caught" in {
val people = List(Person("Joe", 11), Person("Jack", 22))

Expand Down

0 comments on commit f4d3979

Please sign in to comment.