Search code examples
postgresqlscalaplayframeworkslick

Scala Play 2.5 with Slick 3 and Spec2


I have a play application using Slick that I want to test using Spec2, but I keep getting the error org.postgresql.util.PSQLException: FATAL: sorry, too many clients already. I have tried to shut down the database connection by using

val mockApp = new GuiceApplicationBuilder()
val db = mockApp.injector.instanceOf[DBApi].database("default")

...

override def afterAll = {
  db.getConnection().close()
  db.shutdown()
}

But the error persists. The Slick configuration is

slick.dbs.default.driver="slick.driver.PostgresDriver$"
slick.dbs.default.db.driver="org.postgresql.Driver"
slick.dbs.default.db.url="jdbc:postgresql://db:5432/hygge_db"
slick.dbs.default.db.user="*****"
slick.dbs.default.db.password="*****"

Solution

  • getConnection of DbApi either gets connection from underlying data-source's (JdbcDataSource I presume) pool or creates a new one. I see no pool specified in your configuration, so I think it always creates a new one for you. So if you didn't close connection inside the test - getConnection won't help - it will just try to create a new one or take random connection from pool (if pooling is enabled).

    So the solution is to either configure connection pooling:

    When using a connection pool (which is always recommended in production environments) the minimum size of the connection pool should also be set to at least the same size. The maximum size of the connection pool can be set much higher than in a blocking application. Any connections beyond the size of the thread pool will only be used when other connections are required to keep a database session open (e.g. while waiting for the result from an asynchronous computation in the middle of a transaction) but are not actively doing any work on the database.

    so you can just set maximum available connections number in your config:

    connectionPool = 5
    

    Or you can share same connection (you'll probably have to ensure sequentiality then):

    object SharedConnectionForAllTests{ 
      val connection = db.getConnection()
      def close() = connection.close()
    }
    

    It's better to inject it with Spring/Guice of course, so you could conviniently manage connection's lifecycle.