[2.4][slick][heroku] Hikari keeps failing, can not configure bonecp successfully

1,878 views
Skip to first unread message

Christoph Whateverhuis

unread,
Jun 20, 2015, 4:28:46 PM6/20/15
to play-fr...@googlegroups.com
Hi,

I'm at a Hackathon currently and spend like the last two hours with the Heroku-Dev Evangelist trying to get 2.4 with Slick working on Heroku with a Postgres 2.4.1 ... but we keep failing because of the JDBC4 Connection.isValid() error.

It works for me locally with 2.4.1 Postgres. We have tried all the tricks listed on https://www.playframework.com/documentation/2.4.x/Migration24

However, Play seems to ignore ALL the settings. This is in my application.conf:

# play.db.pool=bonecp
play {
  db {
    pool = "bonecp"
  }
}
 
slick.dbs.default.db.pool="bonecp"
slick.dbs.default.pool="bonecp"

slick.dbs.default.driver="slick.driver.PostgresDriver$"
slick.dbs.default.db.driver="org.postgresql.Driver"
slick.dbs.default.db.url="jdbc:postgresql://..."
slick.dbs.default.db.hikaricp.connectionTestQuery="SELECT TRUE"
slick.dbs.default.hikaricp.connectionTestQuery="SELECT TRUE"

Basically, all the config variables seem to be ignored on Heroku: Neither the test query is executed instead of Connection.isValid(), nor is bonecp used.

We've also created our own Procfile, but bonecp is also not being used:

web: target/universal/stage/bin/appname -Dhttp.port=${PORT} -Dslick.dbs.default.db.autoApply -Dslick.dbs.default.db.driver=org.postgresql.Driver -Dslick.dbs.default.db.url=${DATABASE_URL} -Dslick.dbs.default.db.hikaricp.connectionTestQuery="SELECT TRUE" -Dplay.db.pool=bonecp

Here's the full error log from Heroku:

2015-06-20T19:21:52.146692+00:00 app[web.1]: Oops, cannot start the server.
2015-06-20T19:21:52.147678+00:00 app[web.1]:     at com.zaxxer.hikari.pool.BaseHikariPool.getConnection(BaseHikariPool.java:227)
2015-06-20T19:21:52.147750+00:00 app[web.1]:     at com.zaxxer.hikari.pool.BaseHikariPool.getConnection(BaseHikariPool.java:182)
2015-06-20T19:21:52.147824+00:00 app[web.1]:     at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:93)
2015-06-20T19:21:52.147941+00:00 app[web.1]:     at slick.jdbc.JdbcBackend$BaseSession.conn$lzycompute(JdbcBackend.scala:394)
2015-06-20T19:21:52.147892+00:00 app[web.1]:     at slick.jdbc.HikariCPJdbcDataSource.createConnection(JdbcDataSource.scala:131)
2015-06-20T19:21:52.147995+00:00 app[web.1]:     at slick.jdbc.JdbcBackend$BaseSession.conn(JdbcBackend.scala:394)
2015-06-20T19:21:52.148040+00:00 app[web.1]:     at play.api.db.slick.evolutions.internal.DBApiAdapter$DatabaseAdapter.getConnection(DBApiAdapter.scala:54)
2015-06-20T19:21:52.148079+00:00 app[web.1]:     at play.api.db.slick.evolutions.internal.DBApiAdapter$DatabaseAdapter.getConnection(DBApiAdapter.scala:56)
2015-06-20T19:21:52.148117+00:00 app[web.1]:     at play.api.db.evolutions.DatabaseEvolutions.databaseEvolutions(EvolutionsApi.scala:119)
2015-06-20T19:21:52.148165+00:00 app[web.1]:     at play.api.db.evolutions.DatabaseEvolutions.scripts(EvolutionsApi.scala:97)
2015-06-20T19:21:52.148220+00:00 app[web.1]:     at play.api.db.evolutions.DatabaseEvolutions.scripts(EvolutionsApi.scala:112)
2015-06-20T19:21:52.148240+00:00 app[web.1]:     at play.api.db.evolutions.DefaultEvolutionsApi.scripts(EvolutionsApi.scala:77)
2015-06-20T19:21:52.148349+00:00 app[web.1]:     at play.api.db.evolutions.ApplicationEvolutions$$anonfun$play$api$db$evolutions$ApplicationEvolutions$$runEvolutions$1.apply$mcV$sp(ApplicationEvolutions.scala:50)
2015-06-20T19:21:52.148443+00:00 app[web.1]:     at play.api.db.evolutions.ApplicationEvolutions.withLock(ApplicationEvolutions.scala:98)
2015-06-20T19:21:52.148480+00:00 app[web.1]:     at play.api.db.evolutions.ApplicationEvolutions.play$api$db$evolutions$ApplicationEvolutions$$runEvolutions(ApplicationEvolutions.scala:49)
2015-06-20T19:21:52.148532+00:00 app[web.1]:     at play.api.db.evolutions.ApplicationEvolutions$$anonfun$start$1.apply(ApplicationEvolutions.scala:42)
2015-06-20T19:21:52.148590+00:00 app[web.1]:     at play.api.db.evolutions.ApplicationEvolutions$$anonfun$start$1.apply(ApplicationEvolutions.scala:42)
2015-06-20T19:21:52.148627+00:00 app[web.1]:     at scala.collection.immutable.Stream.foreach(Stream.scala:594)
2015-06-20T19:21:52.148756+00:00 app[web.1]:     at play.api.db.evolutions.ApplicationEvolutionsProvider.get$lzycompute(EvolutionsModule.scala:53)
2015-06-20T19:21:52.148687+00:00 app[web.1]:     at play.api.db.evolutions.ApplicationEvolutions.start(ApplicationEvolutions.scala:42)
2015-06-20T19:21:52.148751+00:00 app[web.1]:     at play.api.db.evolutions.ApplicationEvolutions.<init>(ApplicationEvolutions.scala:149)
2015-06-20T19:21:52.148806+00:00 app[web.1]:     at play.api.db.evolutions.ApplicationEvolutionsProvider.get(EvolutionsModule.scala:53)
2015-06-20T19:21:52.148888+00:00 app[web.1]:     at play.api.db.evolutions.ApplicationEvolutionsProvider.get(EvolutionsModule.scala:44)
2015-06-20T19:21:52.148963+00:00 app[web.1]:     at com.google.inject.internal.ProviderInternalFactory.provision(ProviderInternalFactory.java:81)
2015-06-20T19:21:52.149001+00:00 app[web.1]:     at com.google.inject.internal.BoundProviderFactory.provision(BoundProviderFactory.java:72)
2015-06-20T19:21:52.149032+00:00 app[web.1]:     at com.google.inject.internal.ProviderInternalFactory.circularGet(ProviderInternalFactory.java:61)
2015-06-20T19:21:52.149067+00:00 app[web.1]:     at com.google.inject.internal.BoundProviderFactory.get(BoundProviderFactory.java:62)
2015-06-20T19:21:52.149115+00:00 app[web.1]:     at com.google.inject.internal.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:46)
2015-06-20T19:21:52.149142+00:00 app[web.1]:     at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1103)
2015-06-20T19:21:52.149227+00:00 app[web.1]:     at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40)
2015-06-20T19:21:52.149259+00:00 app[web.1]:     at com.google.inject.internal.SingletonScope$1.get(SingletonScope.java:145)
2015-06-20T19:21:52.149418+00:00 app[web.1]:     at com.google.inject.internal.InternalInjectorCreator$1.call(InternalInjectorCreator.java:205)
2015-06-20T19:21:52.149349+00:00 app[web.1]:     at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:41)
2015-06-20T19:21:52.149625+00:00 app[web.1]:     at com.google.inject.internal.InternalInjectorCreator.loadEagerSingletons(InternalInjectorCreator.java:199)
2015-06-20T19:21:52.149493+00:00 app[web.1]:     at com.google.inject.internal.InternalInjectorCreator$1.call(InternalInjectorCreator.java:199)
2015-06-20T19:21:52.149756+00:00 app[web.1]:     at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:110)
2015-06-20T19:21:52.149556+00:00 app[web.1]:     at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1092)
2015-06-20T19:21:52.149883+00:00 app[web.1]:     at com.google.inject.Guice.createInjector(Guice.java:73)
2015-06-20T19:21:52.149678+00:00 app[web.1]:     at com.google.inject.internal.InternalInjectorCreator.injectDynamically(InternalInjectorCreator.java:180)
2015-06-20T19:21:52.149939+00:00 app[web.1]:     at com.google.inject.Guice.createInjector(Guice.java:62)
2015-06-20T19:21:52.149823+00:00 app[web.1]:     at com.google.inject.Guice.createInjector(Guice.java:96)
2015-06-20T19:21:52.149991+00:00 app[web.1]:     at play.api.inject.guice.GuiceBuilder.injector(GuiceInjectorBuilder.scala:126)
2015-06-20T19:21:52.150200+00:00 app[web.1]:     at play.core.server.ProdServerStart$.start(ProdServerStart.scala:52)
2015-06-20T19:21:52.150137+00:00 app[web.1]:     at play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:21)
2015-06-20T19:21:52.150073+00:00 app[web.1]:     at play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:93)
2015-06-20T19:21:52.150325+00:00 app[web.1]:     at play.core.server.ProdServerStart.main(ProdServerStart.scala)
2015-06-20T19:21:52.150263+00:00 app[web.1]:     at play.core.server.ProdServerStart$.main(ProdServerStart.scala:27)
2015-06-20T19:21:52.150504+00:00 app[web.1]: Caused by: java.sql.SQLException: JDBC4 Connection.isValid() method not supported, connection test query must be configured
2015-06-20T19:21:52.150574+00:00 app[web.1]:     at com.zaxxer.hikari.pool.BaseHikariPool.addConnection(BaseHikariPool.java:441)
2015-06-20T19:21:52.150606+00:00 app[web.1]:     at com.zaxxer.hikari.pool.BaseHikariPool$1.run(BaseHikariPool.java:413)
2015-06-20T19:21:52.150722+00:00 app[web.1]:     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
2015-06-20T19:21:52.150658+00:00 app[web.1]:     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
2015-06-20T19:21:52.150788+00:00 app[web.1]:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
2015-06-20T19:21:52.150834+00:00 app[web.1]:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
2015-06-20T19:21:52.150879+00:00 app[web.1]:     at java.lang.Thread.run(Thread.java:745)

I'm completely stuck. I also don't know how I'd debug this - I'm most confused that Play refuses to use bonecp. Judging by https://github.com/playframework/playframework/blob/5d7adcbc246323310f6c9a9ef26555902e0ba3dc/framework/src/play-jdbc/src/main/scala/play/api/db/DefaultDBApi.scala#L25 it seems the pool has to be configured on a per-databae level.

Is it possible that because I use slick, setting bonecp is completely ignored by slick because it doesn't use the Play db infrastructure? Any chance I can fix this real quick'n'dirty for the Hackathon? :)

Thanks,
Christoph

Brett Wooldridge

unread,
Jun 21, 2015, 11:40:33 AM6/21/15
to play-fr...@googlegroups.com

Christoph Whateverhuis

unread,
Jun 21, 2015, 5:29:17 PM6/21/15
to play-fr...@googlegroups.com
Thanks Brett, but this does unfortunately not help.

In fact I'm happily running a Play 2.3 app with Slick on Heroku. This question is specifically about the new Slick integration in 2.4.

Any help is still appreciated ;-)
--
You received this message because you are subscribed to a topic in the Google Groups "play-framework" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/play-framework/nPomE1Z-xb8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to play-framewor...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/49b05831-8b15-463f-8644-f4d4ec9103d7%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Joe Kutner

unread,
Jun 21, 2015, 6:59:28 PM6/21/15
to play-fr...@googlegroups.com
When it's working locally, are you connecting to a local Postgres db, or to the Heroku Postgres db?
To unsubscribe from this group and all its topics, send an email to play-framework+unsubscribe@googlegroups.com.

Joe Kutner

unread,
Jun 21, 2015, 7:11:25 PM6/21/15
to play-fr...@googlegroups.com
Have you tried:
   
slick.dbs.default.db.connectionTestQuery="SELECT TRUE"

I don't have any environment to test this in, but looking at the code makes me think this might be right
https://github.com/slick/slick/blob/e9ab33083bfa1ae642a93d4e52b4ac87b42dc917/slick/src/main/scala/slick/jdbc/JdbcDataSource.scala#L157

Mirco Dotta

unread,
Jun 22, 2015, 3:28:30 AM6/22/15
to play-fr...@googlegroups.com
Hi,

Hi Christoph,


I'm at a Hackathon currently and spend like the last two hours with the Heroku-Dev Evangelist trying to get 2.4 with Slick working on Heroku with a Postgres 2.4.1 ... but we keep failing because of the JDBC4 Connection.isValid() error.

It works for me locally with 2.4.1 Postgres. We have tried all the tricks listed on https://www.playframework.com/documentation/2.4.x/Migration24

If you are migrating from Play 2.3 and Slick 2.1, the following might also be useful https://www.playframework.com/documentation/2.4.x/PlaySlickMigrationGuide

However, Play seems to ignore ALL the settings. This is in my application.conf:

# play.db.pool=bonecp
play {
  db {
    pool = "bonecp"
  }
}
 
slick.dbs.default.db.pool=“bonecp"

slick.dbs.default.pool=“bonecp"

Note: Changing the value of play.db.pool won’t affect what connection pool Slick is using. Furthermore, be aware that any configuration under play.db is not considered by Play Slick.


slick.dbs.default.driver="slick.driver.PostgresDriver$"
slick.dbs.default.db.driver="org.postgresql.Driver"
slick.dbs.default.db.url="jdbc:postgresql://..."
slick.dbs.default.db.hikaricp.connectionTestQuery="SELECT TRUE"
slick.dbs.default.hikaricp.connectionTestQuery="SELECT TRUE”

This should be `slick.dbs.default.db.connectionTestQuery=“SELECT TRUE”`. This is the format Slick 3 expects for the configuration, see Database.forConfig - make sure to expand the forConfig row in the doc)
The decision in play-slick was to let Slick be in control of creating and managing the connection pool. Slick 3 uses HikariCP as default connection pool, but it allows you to hook a different connection pool if needed (you will have to provide an implementation of slick.jdbc.JdbcDataSourceFactory).

Once you have an implementation of JdbcDataSourceFactory, add the following in your config file: `slick.dbs.default.db.connectionPool=<fully qualified name of the type implementing JdbcDataSourceFactory>`. Also, make sure that your implementation is actually a Scala `object`, since that’s what Slick expects (see https://github.com/slick/slick/blob/master/slick/src/main/scala/slick/jdbc/JdbcDataSource.scala#L33).

play-slick should work fine with the above, as long as you don’t need evolutions support. If you do happen to need evolutions support with your new implementation of JdbcDataSourceFactory, then you’ll have to fix something here https://github.com/playframework/play-slick/blob/master/src/evolutions/src/main/scala/play/api/db/slick/evolutions/internal/DBApiAdapter.scala#L46

Hope this helps.

And, of course, if you feel like sharing your work and provide a PR once you are done, please do :-)

Cheers,
Mirco


Thanks,
Christoph

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/a8ddf861-8ebe-4105-89e2-2f275ede2d67%40googlegroups.com.
signature.asc

Christoph Whateverhuis

unread,
Jun 22, 2015, 3:47:13 AM6/22/15
to play-fr...@googlegroups.com
Hi Joe,

thanks for getting back! It works when I use a local Postgres DB and doesn't work if I use the Postgres DB provided by Heroku (also if I use Herokus DB with a local server). I'm not really sure what the difference could be, as both are supposed to be Postgres 9.4.1

You are right - if I remove the "hirakicp" the connectionTestQuery seems to be used instead! I guess this documentation: https://github.com/playframework/playframework/commit/92b9cd2594672e434ebba98b06edda02463936fb is then not applicable for Slick?

Anyway, I just run into the next (slightly different) error:

2015-06-22T07:44:16.174386+00:00 app[web.1]: Oops, cannot start the server.
2015-06-22T07:44:16.175295+00:00 app[web.1]:     at com.zaxxer.hikari.pool.BaseHikariPool.getConnection(BaseHikariPool.java:227)
2015-06-22T07:44:16.175340+00:00 app[web.1]:     at com.zaxxer.hikari.pool.BaseHikariPool.getConnection(BaseHikariPool.java:182)
2015-06-22T07:44:16.175384+00:00 app[web.1]:     at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:93)
2015-06-22T07:44:16.175427+00:00 app[web.1]:     at slick.jdbc.HikariCPJdbcDataSource.createConnection(JdbcDataSource.scala:131)
2015-06-22T07:44:16.175471+00:00 app[web.1]:     at slick.jdbc.JdbcBackend$BaseSession.conn$lzycompute(JdbcBackend.scala:394)
2015-06-22T07:44:16.175559+00:00 app[web.1]:     at slick.jdbc.JdbcBackend$BaseSession.conn(JdbcBackend.scala:394)
2015-06-22T07:44:16.175694+00:00 app[web.1]:     at play.api.db.slick.evolutions.internal.DBApiAdapter$DatabaseAdapter.getConnection(DBApiAdapter.scala:54)
...
2015-06-22T07:44:16.175077+00:00 app[web.1]: java.sql.SQLTimeoutException: Timeout after 1001ms of waiting for a connection.
2015-06-22T07:44:16.176237+00:00 app[web.1]:     at play.api.db.evolutions.ApplicationEvolutions.start(ApplicationEvolutions.scala:42)
2015-06-22T07:44:16.176241+00:00 app[web.1]:     at play.api.db.evolutions.ApplicationEvolutions.<init>(ApplicationEvolutions.scala:149)
...
2015-06-22T07:44:16.180698+00:00 app[web.1]: Caused by: java.lang.NullPointerException
2015-06-22T07:44:16.180741+00:00 app[web.1]:     at com.zaxxer.hikari.pool.BaseHikariPool.addConnection(BaseHikariPool.java:446)
2015-06-22T07:44:16.180783+00:00 app[web.1]:     at com.zaxxer.hikari.pool.BaseHikariPool$1.run(BaseHikariPool.java:413)
2015-06-22T07:44:16.180824+00:00 app[web.1]:     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
2015-06-22T07:44:16.180870+00:00 app[web.1]:     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
2015-06-22T07:44:16.180913+00:00 app[web.1]:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
2015-06-22T07:44:16.180949+00:00 app[web.1]:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
2015-06-22T07:44:16.181000+00:00 app[web.1]:     at java.lang.Thread.run(Thread.java:745)

Seems like the database couldn't be reached at all?! This is strange, as the connection is set by Heroku (see the Procfile I posted). I'll look into this further when I get back from work.

Christoph Whateverhuis

unread,
Jun 22, 2015, 3:57:54 AM6/22/15
to play-fr...@googlegroups.com
Hi Mirco,

thanks for getting back. I was actually not migrating, but starting from scratch (I may migrate the other project in the future).

Thanks for confirming my suspicions regarding Slick not using any of the play.db.* configuration. This wasn't clear for me when I read the documentation (but this may just have been my fault, as during the Hackathon I tried to get this done as quickly as possible...).

HirakiCP is actually completely fine for me, I was just trying to switch to BoneCP to get anything working.

Anyway, I really have to get to work now. Will try to debug some more later today. Thanks for your help!

Mirco Dotta

unread,
Jun 22, 2015, 5:08:47 AM6/22/15
to play-fr...@googlegroups.com
Hi Mirco,

Hi Christoph,

thanks for getting back. I was actually not migrating, but starting from scratch (I may migrate the other project in the future).

Thanks for confirming my suspicions regarding Slick not using any of the play.db.* configuration. This wasn't clear for me when I read the documentation (but this may just have been my fault, as during the Hackathon I tried to get this done as quickly as possible…).

I’m thinking maybe we could provide a warning when play-slick is started and some configuration is found under the `play.db` key. The information itself is in the doc (see https://www.playframework.com/documentation/2.4.x/PlaySlickAdvancedTopics#Connection-Pool), but it’s apparently not easy to find. If you have suggestions on how/where that information should be put to be useful, let me know.

HirakiCP is actually completely fine for me, I was just trying to switch to BoneCP to get anything working.
Anyway, I really have to get to work now. Will try to debug some more later today. Thanks for your help!

On Monday, June 22, 2015 at 9:28:30 AM UTC+2, Mirco Dotta wrote:
Hi,

Hi Christoph,


I'm at a Hackathon currently and spend like the last two hours with the Heroku-Dev Evangelist trying to get 2.4 with Slick working on Heroku with a Postgres 2.4.1 ... but we keep failing because of the JDBC4 Connection.isValid() error.

It works for me locally with 2.4.1 Postgres. We have tried all the tricks listed onhttps://www.playframework.com/documentation/2.4.x/Migration24
signature.asc

Mirco Dotta

unread,
Jun 22, 2015, 5:10:33 AM6/22/15
to play-fr...@googlegroups.com
Hi Joe,

thanks for getting back! It works when I use a local Postgres DB and doesn't work if I use the Postgres DB provided by Heroku (also if I use Herokus DB with a local server). I'm not really sure what the difference could be, as both are supposed to be Postgres 9.4.1

You are right - if I remove the "hirakicp" the connectionTestQuery seems to be used instead! I guess this documentation:https://github.com/playframework/playframework/commit/92b9cd2594672e434ebba98b06edda02463936fbis then not applicable for Slick?

That is the documentation for play-jdbc, not for play-slick. So, indeed, it doesn’t apply to slick.

Is this any help?

It works for me locally with 2.4.1 Postgres. We have tried all the tricks listed onhttps://www.playframework.com/documentation/2.4.x/Migration24

-- 

You received this message because you are subscribed to the Google Groups "play-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/58128fbd-9a31-4e90-94cc-a47198fcf185%40googlegroups.com.
signature.asc

Christoph Whateverhuis

unread,
Jun 26, 2015, 3:36:30 AM6/26/15
to play-fr...@googlegroups.com
To make sure I didn't mess anything up, I started from scratch with the play-scala-intro template (which already includes Slick). I did run into the same issue.

I've uploaded it to Github, so you can see my changes to the template and try for yourself: https://github.com/cneijenhuis/herokuplayslick
I also added some info for those that are new to Heroku.

If you don't want to signup to Heroku, I can also provide you with a Database URL of a Heroku instance so you can test locally, as the same error happens there. Just send me a private email, as I'm not comfortable sharing the credentials in public ;-)

If it's more appropriate, I can also open a Bug Report either with Play! or Slick, as we've got a complete example now.

On a related note, I've submitted a PR with small updates to the Play/Heroku documentation, and I'm happy to do some more documentation work once this works ;-)

Cheers,
Christoph

Mirco Dotta

unread,
Jun 26, 2015, 5:10:30 AM6/26/15
to play-fr...@googlegroups.com
To make sure I didn't mess anything up, I started from scratch with the play-scala-intro template (which already includes Slick). I did run into the same issue.

What is the issue? (We have been discussing too many things in this thread and I’m no longer sure I understand to what particular issue you are referring to, sorry)

If it’s something that be reproduced with the play-scala-intro template, please point me to the incorrect code or configuration.

I've uploaded it to Github, so you can see my changes to the template and try for yourself: https://github.com/cneijenhuis/herokuplayslick

I had a look at it, but again I don’t know what is that I should be looking for :-)

I also added some info for those that are new to Heroku.

If you don't want to signup to Heroku, I can also provide you with a Database URL of a Heroku instance so you can test locally, as the same error happens there. Just send me a private email, as I'm not comfortable sharing the credentials in public ;-)

Oooh, I get it now. You’d like me to have a look at the exception you are getting when running your project in Heroku. Happy to do that, but I’ll be leaving today for a long vacation, so if I don’t get to it by today, it might take a while before I follow up (but I’ll keep a note and come back to you once I’m back ;-)).

If it's more appropriate, I can also open a Bug Report either with Play! or Slick, as we've got a complete example now.

Before opening a ticket we should understand on what project we should do so. I doubt it’s a play-slick issue, since play-slick module it’s really just wiring slick with the play lifecycle and integrating slick with play-evolutions. Basically, my current opinion is that if there is an issue I suspect it will be in either Play, Slick, or HikariCP.

On a related note, I've submitted a PR with small updates to the Play/Heroku documentation, and I'm happy to do some more documentation work once this works ;-)

Awesome!


Cheers,
Christoph

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
signature.asc

Christoph Whateverhuis

unread,
Jun 26, 2015, 6:40:36 AM6/26/15
to play-fr...@googlegroups.com
Yes, I have prepared the repo so you can a) deploy it yourself to Heroku (the stacktrace with the NPE is what you will most likely get) and b) see all the configuration in one place.

Basically, Play doesn't start because HirakiCP doesn't get a connection to Postgres.

No worries if you don't get to it today, enjoy your vacation :-)
You received this message because you are subscribed to a topic in the Google Groups "play-framework" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/play-framework/nPomE1Z-xb8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to play-framewor...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/98F6319A-FFE8-48A7-B546-84E9A6B285AD%40typesafe.com.

Brett Wooldridge

unread,
Jun 26, 2015, 10:17:47 AM6/26/15
to play-fr...@googlegroups.com
Gotta say that is a weird one.  At first I thought, "It's just not possible", the only thing that can NPE on that line is the connection being null.  I have never seen a driver return a null from getConnection().  But...

Some googling for 'org.postgresql.Driver returns null connection' returns this JavaDoc as the first hit:

Try to make a database connection to the given URL. The driver should return "null" if it realizes it is the wrong kind of driver to connect to the given URL.

This is a strong clue.  I have the suspicion that the Procfile is not getting read, and that the URL is ending up null.  If the driver class is defined, but the URL is null then HikariCP ends up in this code:

if (driverClassName != null) {
   Enumeration<Driver> drivers = DriverManager.getDrivers();
   while (drivers.hasMoreElements()) {
      Driver d = drivers.nextElement();
      if (d.getClass().getName().equals(driverClassName)) {
         this.driver = d;
         break;
      }
   }

   if (driver == null) {
      LOGGER.warn("Registered driver with driverClassName={} was not found, trying direct instantiation.", driverClassName);
      try {
         Class<?> driverClass = this.getClass().getClassLoader().loadClass(driverClassName);
         this.driver = (Driver) driverClass.newInstance();
      }
      catch (Exception e) {
         LOGGER.warn("Could not instantiate instance of driver class {}, trying JDBC URL resolution", driverClassName, e);
      }
   }
}

Thus, it is possible for the driver to be loaded, without error but when the driver.connect(url, properties) method is called later, a null can be returned -- causing the NPE.  HikariCP likely needs to call driver.acceptsUrl(url) in this flow.

Generally speaking, it is better not to specify a driverClassName when using a jdbcUrl, unless HikariCP carps about not being able to locate the driver.  These days most drivers self-register and all that is necessary is the URL to resolve them.

Either way, I would expect to see warning logs from that method.  Enabling DEBUG level logging will dump the configuration as HikariCP sees it just before pool initialization.  That is a great place to validate that all the pool properties are as expected (for example, url in this case).


Christoph Whateverhuis

unread,
Jun 27, 2015, 2:31:25 PM6/27/15
to play-fr...@googlegroups.com
Thanks Brett for digging deeper, your link to the Postgres driver pointed me into the right direction!

Long story short, the URL provided by heroku is NOT the correct format for initializing the JDBC driver. Heroku documents here [0] how extract host/port/username/password/dbname and connect to the database. The Play connection pool wrapper handles this correctly [1].

What currently seems to be done is that the URL is taken as-is and plumbed through Slick [2] into Hiraki into the Postgres Driver, which fails and returns null. I manually called driver.acceptsUrl(url) and it returned false. Brett, I think it would be great if Hiraki could check for that and give a much more descriptive error than a NPE ;-)
I'm also wondering why this test [3] doesn't exactly test this case as the Heroku URL doesn't even start with "jdbc:"

Anyway, the question remains who should fix this (as it worked previously for the combo of Play and Slick). I'd say probably not Hiraki, as the method explicitly asks for a jdbc url. Since Slick is supposed to handle all the connection-pool related stuff (and I generally think supporting the shortcut-URLs is a worthwhile feature for Slick to have), I'd suggest Slick...

What do you think?

[0] https://devcenter.heroku.com/articles/heroku-postgresql#jdbc
[1] https://github.com/playframework/playframework/blob/5d7adcbc246323310f6c9a9ef26555902e0ba3dc/framework/src/play-jdbc/src/main/scala/play/api/db/ConnectionPool.scala#L63-L64
[2] https://github.com/slick/slick/blob/e9ab33083bfa1ae642a93d4e52b4ac87b42dc917/slick/src/main/scala/slick/jdbc/JdbcDataSource.scala#L146
[3] https://github.com/brettwooldridge/HikariCP/blob/276b919e04a94c8b58ca4732fb5dec57f9c7896f/hikaricp-common/src/test/java/com/zaxxer/hikari/JdbcDriverTest.java#L66-L83

Joe Kutner

unread,
Jul 6, 2015, 12:29:03 PM7/6/15
to play-fr...@googlegroups.com
I've created a PR against slick for this issue.
https://github.com/slick/slick/pull/1193

Please let me know if there is something I didn't consider, or if this could be more complete.

Christoph Whateverhuis

unread,
Jul 6, 2015, 4:41:57 PM7/6/15
to play-fr...@googlegroups.com
Good work, Joe! I think this should work for the Heroku-use-case.

Note that the Play Connection Pool did some more stuff for MySQL and H2 [0]. I'm not sure if that is still relevant - the H2 stuff was last edited in 2013 [1], the MySQL stuff in 2012 [2]. The main problem I'm seeing here is - if that code is still needed for current versions of MySQL and H2 - that if someone tries to migrate from anorm to Slick, or from Play 2.3 to 2.4, their previously fine shortcut URL will now fail for strange reasons.

Thinking about it, I may actually flip-flop on this and say Play should handle this and not Slick? Maybe some Playframework devs could comment...

[0] https://github.com/playframework/playframework/blob/5d7adcbc246323310f6c9a9ef26555902e0ba3dc/framework/src/play-jdbc/src/main/scala/play/api/db/ConnectionPool.scala#L66-L72
[1] https://github.com/playframework/playframework/commit/26e7dca3c0aaae74ec18bcc8e03c8dc90d87f8f4
[2] https://github.com/playframework/playframework/commit/0906721b4cdf1ed6b7095d6dbd8afa658ec28bc2

PS: I'll write some comments on GitHub regarding some edge cases I noticed while doing a quick code review.

Brett Wooldridge

unread,
Jul 6, 2015, 7:41:49 PM7/6/15
to play-fr...@googlegroups.com
Hi Christoph,

Just so you know, as soon as we (HikariCP) investigated this issue and discovered that the DB was rejecting the URL, we added a check (acceptUrl()) to HikariCP.

HikariCP will now report that no driver was found to accept URL 'xyz'. From our side that is probably about as much as we can do in this case, but should provide a clearer diagnostic path for the user.

Joe Kutner

unread,
Jul 6, 2015, 7:59:36 PM7/6/15
to play-fr...@googlegroups.com
I actually wonder if this should be supported in HikariCP (that is, push the responsibility down, rather than up). Brett, would you accept a PR for DATABASE_URL support similar to the one I linked to in Slick?

The DATABASE_URL is a framework-neutral (i.e. not specific to jdbc) handle to the database. It's been adopted by Play and play-hikaricp. It's also support by other frameworks like Rails, Djanjo, and Node.js.

So rather than rejecting a URL with the protocol "postgres://" it would simply convert it into a JDBC URL.

Brett Wooldridge

unread,
Jul 7, 2015, 2:42:03 AM7/7/15
to play-fr...@googlegroups.com
While we were certainly willing to address what was ostensibly was a bug in HikariCP (not asking the driver to validate the URL), we do believe the responsibility of generating a valid JDBC URL as lying above HikariCP.

Conversely, the URL is a transparent string to HikariCP, and one which the driver can accept or reject based on its own parsing, and therefore driver developers are themselves free to accept a DATABASE_URL if it reaches critical mass.

Christoph Neijenhuis

unread,
Jul 7, 2015, 3:22:31 AM7/7/15
to play-fr...@googlegroups.com
Thanks Brett, this sounds like it will make it easier to debug similar errors in the future, which is great!

I'd also say that Hikari is probably not the right place to fix this root cause of this bug.

--
You received this message because you are subscribed to a topic in the Google Groups "play-framework" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/play-framework/nPomE1Z-xb8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to play-framewor...@googlegroups.com.

Stefan Zeiger

unread,
Jul 13, 2015, 10:17:03 AM7/13/15
to play-fr...@googlegroups.com
On 2015-07-07 8:42, Brett Wooldridge wrote:
While we were certainly willing to address what was ostensibly was a bug in HikariCP (not asking the driver to validate the URL), we do believe the responsibility of generating a valid JDBC URL as lying above HikariCP.

Conversely, the URL is a transparent string to HikariCP, and one which the driver can accept or reject based on its own parsing, and therefore driver developers are themselves free to accept a DATABASE_URL if it reaches critical mass.

I'd make the same argument about Slick but the code needs to go somewhere and if there's no better place for it, IMHO this means accepting https://github.com/slick/slick/pull/1193. Play-JDBC was a good place for it because it is a high-level abstraction but now the alternative would be to put it into Play-Slick which means that an otherwise identical Slick database configuration would accept different kinds of URIs when used standalone or from Play-Slick.

I was thinking about a similar problem when we worked on a DataSource for ConductR a few weeks ago: Slick contains code for managing the lifecycle of a java.sql.Driver used via DriverManager (https://github.com/slick/slick/blob/master/slick/src/main/scala/slick/jdbc/JdbcDataSource.scala#L52-112) and I had to copy this code into our ProxyDataSource project (for wrapping a DriverManager-based configuration in a ProxyDatasource). HikariCP also does the same thing. Why don't we build this abstraction only once? It seems to me that DataSource with Closeable would be the right type. The basic DriverManagerDataSource would be provided by HikariCP. When you want to wrap an existing DataSource (e.g. in HikariDataSource or ProxyDataSource) you have to provide bean properties for the wrapped dataSourceClass and dataSourceProperties and also implement Closeable so you can properly close the wrapped DataSource if it also supports/requires this.

When parsing a config file and applying the bean properties you need a hack for nested configurations (i.e. putting a value of type Properties into a Properties object). HikariCP already does that and Slick could do the same (based on Typesafe Config). If HikariCP exposed such a DataSource, we could even use it directly in Slick for databases with connectionPool=disabled (but it would mean that HikariCP becomes a mandatory dependency).

Getting back to the original topic of this thread, we (Slick or even HikariCP) could have a separate implementation (which delegates back to Hikari's basic implementation for lifecycle management) for Heroku which takes the DATABASE_URL (even grabbing it directly from the env variable) and parses it in the proper way. This would keep this magic rewriting out of the HikariCP core and make it explicit in the configuration.

tl;dr: Wrap DriverManager-style configuration once into a DataSource, then use nested DataSources everywhere.

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

Brett Wooldridge

unread,
Jul 13, 2015, 11:34:45 AM7/13/15
to play-fr...@googlegroups.com
Hi Stefan,

First of all, I'd like to thank Typesafe for selecting HikariCP.

It's midnight here in Tokyo, so I haven't fully digested the proposal above, but I will note that HikariDataSource itself does implement Closeable currently.  HikariCP's DriverDataSource does not currently implement Closeable, though it could if it would help you guys eliminate boilerplate.

Having said that, and as you noted, doing so would impose a dependency on HikariCP that your users may not want.  Without restating an entire post in the HikariCP group about our decision to deprecate our own IConnectionCustomizer class, we basically had this to say:

Finally, and this applies more to connectionCustomizerClassName than connectionInitSql, strange as it may seem for the creators of a connection pool library, we want to avoid features that result in "pool lock-in".  It should be easy for users to switch pools -- not just to HikariCP but away from HikariCP.  In the case of the IConnectionCustomer, as soon as a user implements this interface and their application cannot run without its actions, they have locked their application to HikariCP.  Therefore, we can say with a high degree of confidence that IConnectionCustomer and its related configuration (connectionCustomizerClassNamewill be removed.

Our primary concern for Slick users, or indeed Typesafe, would be "pool lock-in".  We have seen ourselves the technical debt created by exploiting custom extensions in what should be a commodity library (a connection pool), that creates artifical barriers to moving to newer libraries for teams inhereting code several years down the line.

If a path can be found that doesn't lock you guys in (or your users), we'd be happy to take a look and help where we can.

Brett

Stefan Zeiger

unread,
Jul 13, 2015, 1:18:04 PM7/13/15
to play-fr...@googlegroups.com
On 2015-07-13 17:34, Brett Wooldridge wrote:
It's midnight here in Tokyo, so I haven't fully digested the proposal above, but I will note that HikariDataSource itself does implement Closeable currently.  HikariCP's DriverDataSource does not currently implement Closeable, though it could if it would help you guys eliminate boilerplate.

DriverManager is close to what I'm after, except that it should support deregistration of drivers (as far as possible) through an explicit close() call, and be implemented as a Java bean for configuration through a config file via bean properties (like you do it for the "real" DataSource classes provided by database drivers). In HOCON syntax for a Slick Database it could look like this (but it would be very similar for a pure Hikari configuration; everything is the same below the first "properties" elements; from there on it's all bean properties):

mydb {
  connectionPool = HikariCP
  dataSourceClass = com.zaxxer.hikari.util.DriverDataSource
  properties { // Bean properties for DriverDataSource
    driver = org.h2.Driver
    url = "jdbc:h2:mem:test1"
    properties { // getConnection properties in the form of a property of type Properties
      user = foo
      password = secret
    }
  }
}

Any syntax for configuring a pool directly based on DriverManager would be a shortcut for the above, both in Slick (replacing DriverJdbcDataSource with a more generic DataSourceJdbcDataSource) and in HikariCP:

mydb {
  connectionPool = HikariCP
  driver = org.h2.Driver
  url = "jdbc:h2:mem:test1"
  properties {
    user = foo
    password = secret
  }
}

And parsing the Heroku DATABASE_URL could be done in a specialized DataSource to keep this out of the core logic:

mydb {
  connectionPool = HikariCP
  dataSourceClass = com.zaxxer.hikari.util.HerokuDataSource
  properties {
    // databaseUrl = "..."
    // No databaseUrl defined? HerokuDataSource will read it directly from the env variable

  }
}

Our primary concern for Slick users, or indeed Typesafe, would be "pool lock-in".  We have seen ourselves the technical debt created by exploiting custom extensions in what should be a commodity library (a connection pool), that creates artifical barriers to moving to newer libraries for teams inhereting code several years down the line.

If a path can be found that doesn't lock you guys in (or your users), we'd be happy to take a look and help where we can.

Avoiding the lock-in requires duplicate implementations of DriverDataSource in Slick and HikariCP. IMHO it still makes sense under these constraints because they can be made interoperable as long as we agree on an interface that goes a bit beyond DataSource (i.e. also implement Closeable if you need to be closed or if you can wrap another DataSource; and if you configure a nested DataSource, expect to see a Properties value of type Properties). I'm not sure what the defaults should be in Slick if we have duplicate implementations. For connectionPool=disabled it would naturally be Slick's implementation, but should Slick also use that for connectionPool=HikariCP, or should it let HikariCP handle this case?

The situation for HerokuDataSource is similar, but I think lock-in is less of a problem in this case because its only job is to configure a standard DriverDataSource, and switching to a different pool implementation requires you to configure the pool differently anyway. If you think it's too high-level for HikariCP (even as a separate feature that doesn't change the core logic), the case is settled anyway. If you add it to HikariCP, we could use it directly from Slick. Users could even replace the actual connection pool with something else (as long as they don't mind the dependency on HikariCP). Or we just add it to Slick directly.

Christoph Whateverhuis

unread,
Jul 13, 2015, 1:58:30 PM7/13/15
to play-fr...@googlegroups.com
Hi Stefan,

thanks for joining the discussion :-) I just have a very small thing to add:


On Monday, July 13, 2015 at 7:18:04 PM UTC+2, Stefan Zeiger wrote:
  properties {
    // databaseUrl = "..."
    // No databaseUrl defined? HerokuDataSource will read it directly from the env variable
  }

This will not work in cases where one would have several databases configured. Afaik DATABASE_URL is always set as an env variable for the primary database, but one could have additional databases. In this case it is crucial to know the env variable name  and map it to the correct db config.

This is why it's better to manually pass the config on startup and map the env variables to set the config. So one could pass:

-Ddb.default.url=${DATABASE_URL} -Ddb.secondary.url=${HEROKU_POSTGRESQL_RED_URL}

Joe Kutner

unread,
Jul 13, 2015, 5:26:13 PM7/13/15
to play-fr...@googlegroups.com
While the idea of `com.zaxxer.hikari.util.HerokuDataSource` is great for Heroku, DatabaseURL is a platform independent thing, so it should probably be generalized.

DATABASE_URL is derived from the libpq standard format for Postgres connection strings[1]. Now it's used by mysql vendors and others. It's also embraced by Cloud Foundry, and other PaaS providers. So while we're discussing this in the context of Heroku, it's something that I believe should be universally supported.

Consider, for example, an application that is composed of two processes: a Java/JDBC process, and a Python process. The DATABASE_URL could be passed to both without duplicating configuration in a JDBC specific URL. At Heroku, we often recommend that you parse the DATABASE_URL into a JDBC URL in user space, but that's often impossible (such as in the case of Play where all that is set up before you have a chance to run any code). So the only alternative (as is the case for Slick) is to extract the connection config from the DATABASE_URL manually, and hard-code it into the application.conf. I consider this a bad practice.

But let's assume neither Slick nor Hikari will support DATABASE_URL (w/o the user having to change something). Play already supports DATABASE_URL for play-jdbc so it seems natural that it would be supported no matter what the underlying implementation is. How would that work?

Can Play simply parse DATABASE_URL into a JDBC URL and pass it to Slick/Hikari? Are there other edge cases I should consider before digging into the Play sources?

Thanks! This is a great discussion.

[1] http://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNSTRING

Stefan Zeiger

unread,
Jul 14, 2015, 4:29:23 AM7/14/15
to play-fr...@googlegroups.com
On 2015-07-13 23:26, Joe Kutner wrote:
While the idea of `com.zaxxer.hikari.util.HerokuDataSource` is great for Heroku, DatabaseURL is a platform independent thing, so it should probably be generalized.

DATABASE_URL is derived from the libpq standard format for Postgres connection strings[1]. Now it's used by mysql vendors and others. It's also embraced by Cloud Foundry, and other PaaS providers. So while we're discussing this in the context of Heroku, it's something that I believe should be universally supported.

What's the difference to JDBC URLs for Postgres? At first glance https://jdbc.postgresql.org/documentation/head/connect.html seems to be identical, except for the extra "jdbc:" prefix. Is it about taking standard URL-style user/password fields and translating them to parameters?


Consider, for example, an application that is composed of two processes: a Java/JDBC process, and a Python process. The DATABASE_URL could be passed to both without duplicating configuration in a JDBC specific URL. At Heroku, we often recommend that you parse the DATABASE_URL into a JDBC URL in user space, but that's often impossible (such as in the case of Play where all that is set up before you have a chance to run any code). So the only alternative (as is the case for Slick) is to extract the connection config from the DATABASE_URL manually, and hard-code it into the application.conf. I consider this a bad practice.

In an ideal world you would have a DATABASE_URL that is compatible with both, libpq and and JDBC driver, in the first place.


But let's assume neither Slick nor Hikari will support DATABASE_URL (w/o the user having to change something). Play already supports DATABASE_URL for play-jdbc so it seems natural that it would be supported no matter what the underlying implementation is. How would that work?

Play can handle this naturally for play-jdbc because it's responsible for parsing the config syntax and creating the connection pool, so it owns the syntax. For play-slick, the situation is different. The syntax is defined entirely by Slick. While it would be technically possible for play-slick to rewrite the configuration, I don't think it's a good idea. One goal of using Slick's database configuration in Play is to be able to use the same configuration for your Play app and for standalone or non-Play modules which  need to access the same database. If we want to support a different way of configuring the database, it should go into Slick. Encapsulating it in a DataSource (what should be the name of the class?) makes it explicit.


On Monday, July 13, 2015 at 12:58:30 PM UTC-5, Christoph Whateverhuis wrote:

On Monday, July 13, 2015 at 7:18:04 PM UTC+2, Stefan Zeiger wrote:
  properties {
    // databaseUrl = "..."
    // No databaseUrl defined? HerokuDataSource will read it directly from the env variable
  }

This will not work in cases where one would have several databases configured. Afaik DATABASE_URL is always set as an env variable for the primary database, but one could have additional databases. In this case it is crucial to know the env variable name  and map it to the correct db config.

It would only be a default. You could still set the string directly in the config.

Christoph Whateverhuis

unread,
Jul 14, 2015, 3:18:50 PM7/14/15
to play-fr...@googlegroups.com
First of all, I greatly appreciate that you take the time to understand this in detail! However, I'd like to suggest that you view this more as a regression and less as a feature request. It worked this way perfectly fine before (I think I deployed my first Play/Slick app to Heroku at the end of 2012) and IMO it would be best if the new integration would emulate the old behaviour as closely as possible. Both for migrating old projects and also for people who are used to this from anorm who want to try out Slick.


It would only be a default. You could still set the string directly in the config.

Well, I probably can't because my colleagues won't let that pass through code review ;-) Commiting credentials to a git repo is considered a security risk.

I don't see what's wrong with passing the URL at startup with a -D parameter. It seems to be a well-documented feature of typesafe config [0] to set the Java system properties this way to overwrite the application.conf. What you are suggesting seems to be a deviation from how it's usually handled in the typesafe ecosystem.

Again, thanks for taking time to look into this issue!

[0] - https://github.com/typesafehub/config#standard-behavior

Joe Kutner

unread,
Jul 14, 2015, 5:28:44 PM7/14/15
to play-fr...@googlegroups.com

On Tuesday, July 14, 2015 at 3:29:23 AM UTC-5, Stefan Zeiger wrote:
On 2015-07-13 23:26, Joe Kutner wrote:
While the idea of `com.zaxxer.hikari.util.HerokuDataSource` is great for Heroku, DatabaseURL is a platform independent thing, so it should probably be generalized.

DATABASE_URL is derived from the libpq standard format for Postgres connection strings[1]. Now it's used by mysql vendors and others. It's also embraced by Cloud Foundry, and other PaaS providers. So while we're discussing this in the context of Heroku, it's something that I believe should be universally supported.

What's the difference to JDBC URLs for Postgres? At first glance https://jdbc.postgresql.org/documentation/head/connect.html seems to be identical, except for the extra "jdbc:" prefix. Is it about taking standard URL-style user/password fields and translating them to parameters?

There are two differences that I am aware of:
* "postgres" versus "postgresql" :( but mysql and h2 are the same.
* the inclusion of username:password in the libpq format. In JDBC you must separate them, and pass them as args to DriverManager.getConnection

The libpq format is preferable to many people because it obviates the need for separating username and password into their own variables. This makes it easier to *not* add private credentials to flat files in a codebase, which is a very bad practice that is all too common. It reduces portability and it's a security risk. It also makes it more difficult to swap databases in-and-out when doing backups, restores, etc. But I digress...
 

Consider, for example, an application that is composed of two processes: a Java/JDBC process, and a Python process. The DATABASE_URL could be passed to both without duplicating configuration in a JDBC specific URL. At Heroku, we often recommend that you parse the DATABASE_URL into a JDBC URL in user space, but that's often impossible (such as in the case of Play where all that is set up before you have a chance to run any code). So the only alternative (as is the case for Slick) is to extract the connection config from the DATABASE_URL manually, and hard-code it into the application.conf. I consider this a bad practice.

In an ideal world you would have a DATABASE_URL that is compatible with both, libpq and and JDBC driver, in the first place.

But let's assume neither Slick nor Hikari will support DATABASE_URL (w/o the user having to change something). Play already supports DATABASE_URL for play-jdbc so it seems natural that it would be supported no matter what the underlying implementation is. How would that work?

Play can handle this naturally for play-jdbc because it's responsible for parsing the config syntax and creating the connection pool, so it owns the syntax. For play-slick, the situation is different. The syntax is defined entirely by Slick. While it would be technically possible for play-slick to rewrite the configuration, I don't think it's a good idea. One goal of using Slick's database configuration in Play is to be able to use the same configuration for your Play app and for standalone or non-Play modules which  need to access the same database. If we want to support a different way of configuring the database, it should go into Slick. Encapsulating it in a DataSource (what should be the name of the class?) makes it explicit.

Do you mean a DataSource like the slick.jdbc.JdbcDataSource or something else? I'll be happy to do the leg work of implementing this, but I'm a little fuzzy on how it should look.
 

On Monday, July 13, 2015 at 12:58:30 PM UTC-5, Christoph Whateverhuis wrote:

On Monday, July 13, 2015 at 7:18:04 PM UTC+2, Stefan Zeiger wrote:
  properties {
    // databaseUrl = "..."
    // No databaseUrl defined? HerokuDataSource will read it directly from the env variable
  }

This will not work in cases where one would have several databases configured. Afaik DATABASE_URL is always set as an env variable for the primary database, but one could have additional databases. In this case it is crucial to know the env variable name  and map it to the correct db config.

It would only be a default. You could still set the string directly in the config.

I don't think we need to worry about defaulting to the DATABASE_URL env var -- even though that would awesome. There could be some unexpected difficult in terms of precedence. Some people use DATABASE_URL locally and some don't -- they just hard code their dev db config into conf/application.conf and pass in DATABASE_URL in prod.
 
Reply all
Reply to author
Forward
0 new messages