Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make grails service method atomic in multi-user environment

I have a grails service method, load, that I only want one user at a time to be able to run. I have tried using Grails pessimistic lock but it only sometimes works. In my controller, I have:

try {
    def country = Country.lock(id)
    myService.load(country)
} catch (CannotAcquireLockException ex) {
    flash.message = "Another user is modifying ${Country.get(id)}"
}

What is the best way to make load method of myService atomic?

What if I want two methods to be atomic (When one is executing, neither can execute)?

My service's method:

def load(id) {
    def country = Country.get(id)
    country.states.each {
        ...
        it.save(flush: true)
    }
}

Adding the synchronized keyword to this method causes a StaleObjectStateException on the save.

like image 954
Alison Avatar asked Jan 26 '26 09:01

Alison


2 Answers

Grails services are singletons by default which takes care of part of your problem. You should also make your service method synchronized to achieve what you want:

def synchronized load(country) { ... }
like image 144
Gregg Avatar answered Jan 28 '26 01:01

Gregg


You can use @synchronized annotation with a custom synchronization lock. This way you won't be synchronizing this (whole service class), only the given method.

Code sample

class MyCustomService

private final myLock = new Object()

@Synchronized("myLock")
def myRunOneAtATimeMethod(int x, int y)
    return x+y 

More about synchronization: http://groovy.codehaus.org/gapi/groovy/transform/Synchronized.html

like image 26
Andrzej Bobak Avatar answered Jan 27 '26 23:01

Andrzej Bobak