I really like the notion of using akka actors in Java. Basically it is trying to solve the problem of easily writing thread safe code. It does this by passing immutable messages to actors which process them. The idea is that the actor should be stateless and only act upon the immutable object it's given. They also appear to have Software Transactional Memory (STM) for when you do need mutable object and locking.
I have doubts novice programmers which couldn't write a correct singleton or proper thread safe class would be able to use akka to write thread safe code. I could see them creating all kind of actors which are not thread safe.
I did find it was really easy to get a lot of concurrency almost to a fault where my laptop was maxed out and overheating. Of course that may have been my fault as I gave it an infinite computation to work on.
I don't understand why packages don't have remoting support built for the Servlet API. Akka has a remoting support but I always work in a full J2EE container so getting ports opened and bypassing it would not be an option. I would like to know who needs stand alone remoting and is not working with at least Tomcat.
I'll definitely check akka out in more depth.
Showing posts with label concurrency. Show all posts
Showing posts with label concurrency. Show all posts
Saturday, October 1, 2011
Thursday, August 9, 2007
Optimistic Locking in Rails with Active Record for Free...almost
Like other persistence frameworks, ActiveRecord helps us with concurrency issues. This is actually fairly simple, but in general the documentation I have found on this subject has been poor. I will try to sum this up very quickly.
1) Add lock_version
For each table where concurrency is a concern a lock_version column must be added; Rails is then supposed to perform some magic behind the scenes...
In your migration this should look as follows.
table_name.column :lock_version, :integer, :default=>0
Alternatively, if you already have a versioning column in your database you can inform rails of your column by adding the line "set_locking_column 'your_versioning_column_name'" to the associated model class.
2) Catch StaleObjectError
Now that you have added the lock_version column you get concurrency for free. Whenever an attempt occurs to save over the same record version an ActiveRecord::StaleObjectError will be raised.
So now you can update your controllers to catch StaleObjectErrors and handle these however you wish...
This would look something like this.
def some_updating_method(an_object)
an_object.update_attributes(params[:an_object])
rescue ActiveRecord::StaleObjectError => e
flash[:notice] = "This record changed while you were editing it. Please try again."
#maybe perform a redirect here...
end
3) But Wait! Update methods aren't actually passed objects that's too much overhead!
How observant you are. This is where most of the example tend to fall short. In fact, try implementing your update method exactly like Recipe 3.18 from the Rails Cookbook and see what happens...
Generally an update method actually looks more like this.
def update
my_object = MyObject.find(params[id])
my_object.update_attributes(params[:my_object])
end
While this will stop to users from updating at the exact same time this isn't exactly what we want in many cases. More often than not we want to prevent two users from editing over each other without knowing.
This is easily fixed with the following...
def edit
my_object = MyObject.find(params[id])
session[lock_version] = my_object.lock_version
# whatever we want edit to do
# ...
# ...
# call update...
end
Now we update update (har har) to detect the concurrency issue...
def update
if my_object.lock_version != session[:lock_version]
raise ActiveRecord::StaleObjectError
end
my_object = MyObject.find(params[id])
my_object.update_attributes(params[:my_object])
rescue ActiveRecord::StaleObjectError => e
flash[:notice] = "This record changed while you were editing it. Please try again."
#maybe perform a redirect here...
end
Hopefully this helps someone out. If you have a better/cleaner way of doing this, let me know.
1) Add lock_version
For each table where concurrency is a concern a lock_version column must be added; Rails is then supposed to perform some magic behind the scenes...
In your migration this should look as follows.
table_name.column :lock_version, :integer, :default=>0
Alternatively, if you already have a versioning column in your database you can inform rails of your column by adding the line "set_locking_column 'your_versioning_column_name'" to the associated model class.
2) Catch StaleObjectError
Now that you have added the lock_version column you get concurrency for free. Whenever an attempt occurs to save over the same record version an ActiveRecord::StaleObjectError will be raised.
So now you can update your controllers to catch StaleObjectErrors and handle these however you wish...
This would look something like this.
def some_updating_method(an_object)
an_object.update_attributes(params[:an_object])
rescue ActiveRecord::StaleObjectError => e
flash[:notice] = "This record changed while you were editing it. Please try again."
#maybe perform a redirect here...
end
3) But Wait! Update methods aren't actually passed objects that's too much overhead!
How observant you are. This is where most of the example tend to fall short. In fact, try implementing your update method exactly like Recipe 3.18 from the Rails Cookbook and see what happens...
Generally an update method actually looks more like this.
def update
my_object = MyObject.find(params[id])
my_object.update_attributes(params[:my_object])
end
While this will stop to users from updating at the exact same time this isn't exactly what we want in many cases. More often than not we want to prevent two users from editing over each other without knowing.
This is easily fixed with the following...
def edit
my_object = MyObject.find(params[id])
session[lock_version] = my_object.lock_version
# whatever we want edit to do
# ...
# ...
# call update...
end
Now we update update (har har) to detect the concurrency issue...
def update
if my_object.lock_version != session[:lock_version]
raise ActiveRecord::StaleObjectError
end
my_object = MyObject.find(params[id])
my_object.update_attributes(params[:my_object])
rescue ActiveRecord::StaleObjectError => e
flash[:notice] = "This record changed while you were editing it. Please try again."
#maybe perform a redirect here...
end
Hopefully this helps someone out. If you have a better/cleaner way of doing this, let me know.
Labels:
concurrency,
optimistic locking,
rails,
ruby,
ruby on rails
Subscribe to:
Posts (Atom)