In my rails application, I have some code like this:
def foo
if object_bar_exists
raise "can't create bar twice!"
end
Bar.create
end
Which could be invoked by two different requests coming into the application server. If this code is run by two requests simultaneously, and they both run the if
check at the same time, neither will find the other's bar
, and 2 bar
s will be created.
What's the best way to create a "mutex" for "the collection of bars"? A special purpose mutex table in the DB?
update
I should emphasize that I cannot use a memory mutex here, because the concurrency is across requests/processes and not threads.
Object Lock can help prevent objects from being deleted or overwritten for a fixed amount of time or indefinitely. You can use Object Lock to help meet regulatory requirements that require WORM storage, or to simply add another layer of protection against object changes and deletion.
Lock an object in placeSelect the Inspector from the toolbar. In the Inspector, select the Lock tab. Select an object (or objects) on the canvas that you would like to lock. Choose Lock.
Press Ctrl+Alt+L.
The best thing to do is perform your operations in a DB transaction. Because you will probably eventually have multiple applications running and they very possibly won't share memory, you won't be able to create a Mutex lock on the application level, especially if those two application services are running on entirely different physical boxes. Here's how to accomplish the DB transaction:
ActiveRecord::Base.transaction do
# Transaction code goes here.
end
If you want to ensure a rollback on the DB transaction then you'll have to have validation enabled on the Bar class so that an invalid save request will cause a rollback:
ActiveRecord::Base.transaction do
bar = Bar.new(params[:bar])
bar.save!
end
If you already have a bar object in the DB, you can lock that object pessimistically like this:
ActiveRecord::Base.transaction do
bar = Bar.find(1, :lock => true)
# perform operations on bar
end
If they all the requests are coming into the same machine, and the same ruby virtual machine, you could use Ruby's built in Mutex class: Mutex Docs.
If there are multiple machines or rvms, you will have to use a database transaction to create / get the Bar object, assuming it's stored in the db somehow.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With