开发者

How do avoid race conditions in a Ruby on Rails application?

I'm developing a Rails application in which each subdomain has a separate database. And I'm doing something like this.

#app/controller/application_controller.rb开发者_C百科
class ApplicationController < ActionController::Base
  before_filter :select_database

  private
  def select_database
    MyModel.use_database(request.subdomains.first)
  end
end

#app/model/my_model.rb
class MyModel < ActiveRecord::Base

  def self.use_database path
    establish_connection :adapter => 'sqlite3', :database =>
      File.join(RAILS_ROOT, "db", "sqlite3", path)
  end
end

Now, in production mode, requests come and execute in this order.

  1. Request "A" comes for subdomain a.example.net and MyModel establishes a connection with database "a".
  2. Now another request "B" comes for subdomain b.example.net and MyModel establishes a connection with database "b".
  3. Now if request "A" tries to do a MyModel.find_*() which database would it access? "a" or "b"?

I believe that this is what we call "thread safety" or "race condition", and if this is so, then how can we avoid it while implementing an application using one database per subdomain?

In the above question, my assumption is that executing two requests simultaneously is a normal behaviour for production servers. Or is there some better approach. I don't have much experience of production servers, so please advice.


It seems like you are using Replications... However I do suggest that you watch the following casts from newrelic to get a better idea on DB scaling:

Scaling Your Database - Part 1

Scaling Your Database - Part 2


If there are two models and two databases, why not subclass your MyModel for each database?

class MyModelDomainA < MyModel
  DBA_PATH = "first/db/path"
  def self.use_database
    establish_connection :adapter => 'sqlite3', :database => File.join(RAILS_ROOT, "db", "sqlite3", DBA_PATH)
  end
end
# then in controller:
def select_database
  # or whatever string-manipulation you need to do... 
  # even have a lookup hash to get the correct model?
  model_klass = "MyModel#{request.subdomains.first.capitalize}"
  model_klass.constantize.use_database
end

etc. Obviously this only works if you have a small, fixed number of domain/database pairs. But if so - it means that anybody coming into DomainA will always access the database for Domain A = no race conditions.

Generally, I find that unless you're hacking kernel code, the solution to a race condition is not thread-safety... but to re-think the problem.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜