Calling close()

820 views
Skip to first unread message

Richard Rodseth

unread,
May 6, 2015, 12:34:46 AM5/6/15
to scala...@googlegroups.com
I'm enjoying exploring Slick 3.0, but I'm unclear on the topic of closing databases.

>>>
Since a Database instance can now have an associated connection pool and thread pool, it is important to call close when you are done using it, so that these pools can be shut down properly. You should take care to do this wen you migrate to the new Action-based API. As long as you exclusively use the old API (and do not configure a session pool), it is not strictly necessary.
<<<

In my 2.1 code, the DAO methods have an implicit session parameter. I assume I could pass a Database instance in similar fashion.

Surely the code linked below is wrong? Creating a Database on each method call?  Calling close even if the future has not completed?

I couldn't find any guidance in the Activator templates. Hello-Slick calls Await, and MultiDB uses Future.andThen:

.andThen { case _ => sqlitedb.close }

but they are not typical web apps.

As an aside, I think the documentation and examples would be clearer if they used more intermediate vals, with types included, rather than emphasizing brevity.

Thanks
Richard

http://blog.knoldus.com/2015/03/03/play-with-reactive-slick-a-simple-crud-application-in-play-framework-using-slick-3-0/


object EmployeeDAO {
 
  val employees = TableQuery[Employees]
 
  def db: Database = Database.forDataSource(DB.getDataSource())
 
  def filterQuery(id: Long): Query[Employees, Employee, Seq] =
    employees.filter(_.id === id)
 
  def findById(id: Long): Future[Employee] =
    try db.run(filterQuery(id).result.head)
    finally db.close



Stefan Zeiger

unread,
May 6, 2015, 3:48:29 AM5/6/15
to scala...@googlegroups.com
On 2015-05-06 6:34, Richard Rodseth wrote:
In my 2.1 code, the DAO methods have an implicit session parameter. I assume I could pass a Database instance in similar fashion.

Surely the code linked below is wrong? Creating a Database on each method call?  Calling close even if the future has not completed?

The Knoldus blog post does it wrong. This is pointed out in the comments and the actual repo has been fixed but the post still shows the broken version. Create one Database instance when you start your app, close it when your app shuts down. Closing it before all database actions have completed should be safe (i.e. no race conditions when called concurrently) but may cause the outstanding and currently running actions to fail. That's why we Await() in the samples. In a web app this would not be an issue because you're killing the whole app and interrupting service anyway.

--
Stefan Zeiger
Slick Tech Lead
Typesafe - Build Reactive Apps!
Twitter: @StefanZeiger

Richard Rodseth

unread,
May 6, 2015, 8:49:03 AM5/6/15
to scala...@googlegroups.com
Thanks for the clarification. I will just use constructor injection in that case.
--

---
You received this message because you are subscribed to the Google Groups "Slick / ScalaQuery" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scalaquery+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/scalaquery/5549C74A.6040307%40typesafe.com.
For more options, visit https://groups.google.com/d/optout.

Cameron Joannidis

unread,
May 7, 2015, 6:53:26 PM5/7/15
to scala...@googlegroups.com
I'm having a similar confusion with the way db connections are managed. I've got a very basic setup (perhaps part of the issue):

postgres = {
  driver = "org.postgresql.Driver"
  url: "jdbc:postgresql://localhost:5432/testdb"
}

loaded in via a trait Database:
trait Database {
  lazy val db = Database.forConfig("postgres")
}

which is then mixed in where needed so it should be the same db object. My issue is that when I do:

db.run(query)

the connections never seem to be releases properly and I end up with SQLTimeout exceptions when i try and do enough things that require the db.


I've tried a few other things I've seen floating around the web:


try db.run(query)

finally db.close()


gives me (as expected):

java.sql.SQLException: Interrupted during connection acquisition

        at com.zaxxer.hikari.pool.BaseHikariPool.getConnection(BaseHikariPool.java:220) ~[HikariCP-2.3.7.jar:na]

        at com.zaxxer.hikari.pool.BaseHikariPool.getConnection(BaseHikariPool.java:182) ~[HikariCP-2.3.7.jar:na]

        at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:93) ~[HikariCP-2.3.7.jar:na]

        at slick.jdbc.HikariCPJdbcDataSource.createConnection(JdbcDataSource.scala:131) ~[slick_2.11-3.0.0.jar:na]

        at slick.jdbc.JdbcBackend$BaseSession.conn$lzycompute(JdbcBackend.scala:394) ~[slick_2.11-3.0.0.jar:na]

Caused by: java.lang.InterruptedException: null

        at java.util.concurrent.locks.AbstractQueuedLongSynchronizer.tryAcquireSharedNanos(AbstractQueuedLongSynchronizer.java:1104) ~[na:1.8.0_31]

        at com.zaxxer.hikari.util.ConcurrentBag.borrow(ConcurrentBag.java:134) ~[HikariCP-2.3.7.jar:na]

        at com.zaxxer.hikari.pool.BaseHikariPool.getConnection(BaseHikariPool.java:201) ~[HikariCP-2.3.7.jar:na]

        at com.zaxxer.hikari.pool.BaseHikariPool.getConnection(BaseHikariPool.java:182) ~[HikariCP-2.3.7.jar:na]

        at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:93) ~[HikariCP-2.3.7.jar:na]


db.run(query) andThen { case _ => db.close() }


gives me 

java.util.concurrent.RejectedExecutionException: Task slick.backend.DatabaseComponent$DatabaseDef$$anon$2@63ff7e8c rejected from java.util.concurrent.ThreadPoolExecutor@379febc7[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 1]

        at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047) ~[na:1.8.0_31]

        at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823) ~[na:1.8.0_31]

        at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369) ~[na:1.8.0_31]

        at scala.concurrent.impl.ExecutionContextImpl$$anon$1.execute(ExecutionContextImpl.scala:136) ~[scala-library-2.11.6.jar:na]

        at slick.backend.DatabaseComponent$DatabaseDef$class.runSynchronousDatabaseAction(DatabaseComponent.scala:224) ~[slick_2.11-3.0.0.jar:na]


What is the correct way to deal with db connections in slick 3.0.0?

Richard Rodseth

unread,
May 7, 2015, 7:57:55 PM5/7/15
to scala...@googlegroups.com
Hope I don't have a senior moment and embarrass myself, but I'm pretty sure you're getting multiple db instances with the trait you describe. In other words, just because that's a lazy val, doesn't make it a singleton.


--

---
You received this message because you are subscribed to the Google Groups "Slick / ScalaQuery" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scalaquery+...@googlegroups.com.

Cameron Joannidis

unread,
May 7, 2015, 8:22:35 PM5/7/15
to scala...@googlegroups.com
Ah yes... silly mistake... This is why I shouldn't post questions when sleep deprived!

Thank you Richard.
Reply all
Reply to author
Forward
0 new messages