We are having problems with race conditions in our rails application. Here is some (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 happens in what is create_or_update_sending_messagecalled from two processes. Both treat the message collection as empty, so both create a new message. Then the third process loads the question, modifies it, tries to save it, and we get an error thrown in a place where there is no real problem.
I can come up with several ways to avoid this if we develop from scratch, but, unfortunately, is create_or_update_sending_messagetoo deep in legacy code to be practical.
. , - .
?
def create_or_update_sending_message
self.optimistically_lock do |lock|
sending_message = messages.detect {|m| m.status == 'sending'}
sending_message ||= messages.create_with_optimistic_lock lock, :status => 'sending'
sending_message
end
end
?