Can I use optimistic locking of an object to guard its associations?
We're running into problems with a race condition in our rails app. Here's a bit of (simplified) code before I explain:
class Message < ActiveRecord::Base
belongs_to :question
end
class Question < ActiveRecord::Base
has_many :messages
def create_or_update_sending_message
sending_message = messages.detect {|m| m.status == 'sending'}
sending_message ||= messages.create :status => 'sending'
sending_message
end
def validate
errors.add_to_base('cannot have multiple sending messages') if messages.select {|m| m.status == 'sending'}.count > 1
end
end
What's happening is that create_or_update_sending_message
is being called from two processes. Both see the messages collection as empty, so both create a new message. Then a third process loads the question, modifies it, tries to save it, and we get an error thrown in a place that isn't where the actual problem occurred.
I can think of a few ways to avoid this if we were designing from scratch, but unfortunately create_or_update_sending_message
is too deep in legacy code for this to be practical.
We have optimistic locking enabled for our Question model. It doesn't help because the question isn't being saved - only its messages are.
Is there a way to use the optimistic locking on the question to guard against the saving of the creation of the message? So it would look something like
def create_or_update_sending_message
self.optimistically_lock do |lock|
sending_message = messages.detect {|m| m.status == 'sending'}
sending_message ||= 开发者_StackOverflowmessages.create_with_optimistic_lock lock, :status => 'sending'
sending_message
end
end
Does that even make sense from a database point of view?
精彩评论