edulify / play-hikaricp.edulify.com

HikariCP Plugin for Playframework 2.2.x and 2.3.x

Home Page:http://edulify.github.io/play-hikaricp.edulify.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

allow play to start when a configured db is unavailable

richardhundt opened this issue · comments

Hi There, thanks for the project!

The initializationFailFast = false semantics are not what I expected. I was hoping to be able to start the application even if a configured db is unavailable (a data warehouse we're connecting to sometimes goes down for maintenance).

We could extend your plugin and probably figure out how to do that, but before we do, was wondering if you had any plans for adding this, or pointers for us?

Thanks!
Richard

It seems to me that the culprit is this (HikariCPPlugin.scala):

  override def onStart() {
    play.api.Logger.info("Starting HikariCP connection pool...")
    hikariCPDBApi.datasources.map { ds =>
        try {
          ds._1.getConnection.close()
          app.mode match {
            case Mode.Test =>
            case mode => Logger.info("database [" + ds._2 + "] connected at " + dbURL(ds._1.getConnection))
          }
        } catch {
          case NonFatal(e) => {
            throw databaseConfig.reportError(ds._2 + ".url", "Cannot connect to database [" + ds._2 + "]", Some(e.getCause))
          }
        }
    }
  }

It shouldn't try to obtain db connections from the data source if the initializationFailFast flag is set to false.

@mberndt123 exactly. Maybe we could move this check to HikariCPDBApi and do as you said.

@richardhundt, I don't think you have to fork and maintain a separated version of the plugin. Please, submit a pull request and I will take a look at it ASAP.

I don't think the check is needed at all. HikariCP itself will populate the connection pools on initialization and throw a PoolInitializationException if it fails. If you want to check for that, I suggest catching the exception.
I also think it would be better to make hikariCPDBApi a var and initialize it onStart. lazy vals are thread safe and thus incur a locking overhead every time they're accessed, which afaics simply isn't necessary in this case.

@mberndt123, the check exists to ensure that users who have a misconfiguration in the pool are clearly notified about the error (using the play way). This is a good behavior for fail fast pools.

@megazord,You seem to be misunderstanding what's happening here. Let's assume there's a bad config. There are two cases to consider:

Case 1: initializationFailFast = true
onStart is called. It then uses the lazy val hikariCPDBApi, leading to its initialisation. HikariCPDBApi's constructor now calls the HikariDataSource constructor, which tries to populate the pool and throws an exception due to the bad config. The ds._1.getConnection.close() is thus never run, making it useless.
Case 2: initializationFailFast=false
Like before, except that the HikariDataSource constructor doesn't throw. In this case, the ds._1.getConnection.close() is not only useless but actively harmful, as it defeats the purpose of the initializationFailFast=false flag.

So no matter how you look at it, there's no reason for the check to be there. I also suggest getting rid of the lazy val, it clearly proved to be too subtle.

@mberndt123

Oh I see, you are right. Please submit a PR with proper tests and I will take take a look ASAP.

@richardhundt and @mberndt123

A new version (2.0.3) was released just right now. Please, see the commit above for more information about what changed.