Skip to content

Instantly share code, notes, and snippets.

@eamonn-webster
Last active December 16, 2015 02:39
Show Gist options
  • Save eamonn-webster/5364431 to your computer and use it in GitHub Desktop.
Save eamonn-webster/5364431 to your computer and use it in GitHub Desktop.
rails mysql database backed lock
class TimeoutError < StandardError
end
# used to prevent code running on the same object twice
def answer
begin
eq = EnrollmentQuestion.find_by_enrollment_id_and_question_id(@enrollment.id, @question.id)
Lock.new(eq,0).synchronize do
if @enrollment.is_valid_attempt?(@question)
...
end
respond_to do |format|
...
end
end
rescue TimeoutError
redirect_somewhere
end
end
class Lock
def initialize(name,timeout)
@name = generate_name(name)
@timeout = timeout || 10
end
def synchronize(&block)
lock
begin
block.call()
ensure
release
end
end
private
def generate_name(name)
if name.respond_to?(:to_model)
"#{ActiveModel::Naming.singular(name)}_#{name.to_model.to_key.join('_')}"
else
name
end
end
def lock
res = ActiveRecord::Base.connection.execute("SELECT GET_LOCK('#{@name}',#{@timeout});")
res = res.first if res
res = res.first if res
#Rails.logger.error "lock(#{@name},#{@timeout}) => #{res}"
raise TimeoutError, "Getting Lock #{@name} timeout" unless res == 1
end
def release
res = ActiveRecord::Base.connection.execute("SELECT RELEASE_LOCK('#{@name}');")
res = res.first if res
res = res.first if res
#Rails.logger.error "release(#{@name}) => #{res}"
res
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment