0

In our application, we are using grails framework and SQL server for database. We have multiple sites and those sites can have multiple users (a few users) and if they are accessing the same method via AJAX that can cause issue so we made the that method as synchronized method and to minimize the database interaction we are storing data in map on site basis since all the user from one site will get the same data, and if the data is older than 10 seconds we get the data from database and update the map object. Here we are getting a lot of database connection close issues on the very first line of synchronized method where we are getting site object from database. What is the issue here and how we can resolve the issue?

def synchronized getData(params){
  Site site = Site.get(params.siteId)
  // Here we are checking whether site data does not exists in map
  // or the data expired (10 second older data) then we get data from
  // database and update the map object

  // Then here we create new list object from the data in map object

  return list
}
Aimery
  • 1,559
  • 1
  • 19
  • 24
  • Do you have an error you can share? Would be helpful to see what the error is. Without more info it's hard to understand the context of the error from the little code provided. How are you accessing the DB? Are you using and storing a single connection in the service? If so, the connection could have a timeout or time-to-live and is being closed between long call intervals. Besides that, you may be better off having a scheduled service run independently of the user requests that just replaces the map every 10 minutes - then the user never has to wait. – Townsfolk Sep 12 '19 at 20:43

1 Answers1

-1

Difficult to figure out the exact problem without more information here. Several things stand out...

I'm not especially familiar with using the synchronized keyword in front of a service method, I would recommend trying the synchronized annotation with a static object key:

private static final myLock = new Object()

@Synchronized("myLock")
void getData() {
  //do stuff
}

or synchronizing explicitly within the method

void getData() {
  synchronized(myLock) {
    //do stuff
  }
}

I don't know if that's related to your connection closing issues, but worth a try.

But also notably, grails and hibernate provide caching of database retrieves, so if you're loading the same data that's been loaded into hibernate cache, you don't need to cache this in a Map locally... grails is already doing that for you. Site site = Site.get(params.siteId) will NOT make a database call if it's been called recently and is already cached by the framework.

I would strongly suggest running some performance checks just making that call vs. caching in a Map object, especially if you're expiring in ~10s anyway.

Trebla
  • 1,164
  • 1
  • 13
  • 28
  • "but note that in grails 3, services are prototype scoped by default" - I don't think that is true. – Jeff Scott Brown Sep 12 '19 at 13:52
  • By default we configure all of your services with `singleton` scope. If you want them to be anything else (`prototype` or otherwise), that has to be expressed. – Jeff Scott Brown Sep 12 '19 at 14:56
  • Obviously you're right, clearly I had that backwards, I just remembered that we ran into problems when the default scope changed between grails 2 and grails 3 and must have reversed the direction in my brain. Will edit my answer to remove the misdirection – Trebla Sep 23 '19 at 18:37
  • For a singleton is there some reason that you would still want `myLock` ? – Jeff Scott Brown Sep 24 '19 at 00:01
  • "we ran into problems when the default scope changed between grails 2 and grails 3 and must have reversed the direction in my brain" - I think services were singleton by default in Grails 2 as well. – Jeff Scott Brown Sep 24 '19 at 00:02
  • No, as a singleton, I can't think why a separate lock object would work differently. Just a suggestion as something else to try for the OP assuming the only change between "working" and "not working" is the keyword on the method. Clearly I'm remembering something incorrectly about default scope (this was several years ago) and I suppose it's entirely possible I misdiagnosed the issue in the first place (or it was always an issue, but we only noticed when we moved to grails 3 by complete coincidence). – Trebla Sep 24 '19 at 12:18