Mar 21, 2011

Rails Critical Section through MySQL

The Problem

We have problem with agreeing with a comment in Squeks. If the same user agrees on the same comment at the same time, then 2 identical records of comment_agree will be created.

Therefore, we need some kind of critical section in order to prevent that situation.

The Solution

We use Named Lock provided by MySQL. You can use these two statements:


SELECT GET_LOCK('lock1',10);
SELECT RELEASE_LOCK('lock1');


Anyway, it's more convenient to build a class in order to deal with this:


class Lock
def self.lock(name)
return ActiveRecord::Base.connection.execute("SELECT GET_LOCK('#name}',60);").fetch_row[0]
end

def self.release(name)
ActiveRecord::Base.connection.execute("SELECT RELEASE_LOCK('#{name}');")
end

def initialize(*name)
@lock_name = Lock.generate_name(name)
end

def synchronize(&block)

Lock.lock(@lock_name) rescue (raise "Getting Lock #{@lock_name} timeout")

block.call()

while true
Lock.release(@lock_name) rescue next
break
end

end

private
def self.generate_name(names)
names.map{ |t| t.to_s}.join('--')
end
end