Question

We have a grails app, which has various domain objects stored in the grails db. The app connects to a second DB, runs some raw sql, and displays the results in a table. Its basically a reporting server.

We are connnecting to the second db by specifying a second datasource in DataSource.groovy e.g.:

dataSource_target {
dialect = org.hibernate.dialect.MySQLInnoDBDialect
pooled = true
jmxExport = true
driverClassName = "com.mysql.jdbc.Driver"
username = "bla"
password = "bla"
}

Then in the controller, we have

static mapping = {
    datasource 'ALL'
 }

Then in the service, we have:

         con = new Sql(dataSource_target)
         rows = con.rows(sql)

It works but with two big problem:

  1. If the reporting app cant connect to the second "target" datasource when you do grails run-app, it wont start.

  2. Once running, if the app loses connection to the target DB, it wont try to reconnect, you have to stop and start the entire grails app again.

We need something more robust - the target DB is only called when the user decides to run a report - its not run when the app starts, and should try and connect (or reconnect) when we call con = new Sql(datasource).

Any ideas how we might achieve this? Ie. a way to connect to an aribtrary DB at run time, pull back some rows, and if the connection to the target db is lost, then reestablished, next time you run a report it should still work. Also, if the app is started when the target db is not there, it should still start, as it has no dependency on it at start up.

Thanks,

Was it helpful?

Solution

You might consider adding some additional properties to allow it to try and reconnect. For example:

dataSource_target {
  dialect = org.hibernate.dialect.MySQLInnoDBDialect
  pooled = true
  jmxExport = true
  driverClassName = "com.mysql.jdbc.Driver"
  username = "bla"
  password = "bla"
  properties {
    maxActive = -1
    minEvictableIdleTimeMillis=1800000
    timeBetweenEvictionRunsMillis=1800000
    numTestsPerEvictionRun=3
    testOnBorrow=true
    testWhileIdle=true
    testOnReturn=true
    validationQuery="SELECT 1"
  }
}

I suggest you alter the properties to suit your needs. This however, will not address the issue of the database not being available when the application is started.

To avoid that, you have to get away from using Grails data sources. In that case you would need to define your datasource in your service that is making the calls to the database.

def db = [
  url:'jdbc:hsqldb:mem:testDB', 
  user:'sa', 
  password:'', 
  driver:'org.hsqldb.jdbc.JDBCDriver'
]
def sql = Sql.newInstance(db.url, db.user, db.password, db.driver)

Of course, modify this to suit your needs. You may even pull these settings from Config.groovy instead of hard coding them (highly recommended).

OTHER TIPS

To get those values dynamically from your application.yml, I guess it depends on which version of grails 3 since I know the config for dsn has changed slightly on 3.2.8:

def db = [:]
def dataSources = Holders.grailsApplication.config.dataSources
db.user = dataSources.dataSource_otherDsn.username
db.password = dataSources.dataSource_otherDsn.password
db.driver = dataSources.dataSource_otherDsn.driverClassName
if (Environment.current == Environment.DEVELOPMENT) {
    db.url = Holders.grailsApplication.config.environments.development.dataSources.dataSource_otherDsn.url
} else if (Environment.current == Environment.PRODUCTION) {
    db.url = Holders.grailsApplication.config.environments.production.dataSource.dataSource_otherDsn.url

}
def sql = Sql.newInstance(db.url, db.user, db.password, db.driver)

Since the config values was split over different segments of the .yml file I had to look for the bits in the different locations.

Whilst this was in a service and GrailsApplicationAware with standard grailsApplication failed to pick up with Holders.grailsApplication worked. Although directly calling service is BootStrap so may relate to start up process requirements.

Eitherway it will make it more dynamic this way.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top