With the ever more frequent use of multiple servers and worker processes, issues which only occur when specific tasks are running in parallel become ever more likely to happen.
In this talk Marcos talks about some rails concurrency limitations you need to be aware of, including why you should never trust rails to check for uniqueness, why mysql can't do optimistic locking with retrying by default and how to fix it, how to properly choose between optimistic and pessimistic locking, how parallel processes can cause deadlocks even if you're not using locks, why you should never have serialized attributes in rows that might be edited in parallel, and why rails commits your transactions before they finish in case your multi threaded process is killed and how to prevent it from leaving your database on an inconsistent state.
20. :dependent
=> :destroy
class Comment < ActiveRecord::Base
belongs_to :post
validates_presence_of :post
end
class Post < ActiveRecord::Base
has_many :comments, :dependent => :destroy
end
66. No pessimistic
locking!
class Comment
after_create :update_posts_count
def update_posts_count
self.posts.increment :comments_count
end
end
class Posts
after_update :update_comments
def update_comments
comments.each {|c| c.published = self.published; c.save}
end
end
68. Transac
Transaction 1
SELECT * FOR
tion 2
UPDATE
FROM `comments`
WHERE `id` = 1 SELECT * FOR
UPDATE
locked.. FROM `posts`
WHERE `id` = 1
SELECT * FOR
UPDATE
FROM `posts` DEADLOCK!
WHERE `id` = 1
SELECT * FOR
UPDATE
FROM `comments`
WHERE `id` = 1
75. No longer
deadlocks!
class Comment
after_create :update_posts_count
def update_posts_count
self.posts.increment :comments_count
end
end
class Posts
before_update :update_comments
def update_comments
comments.each {|c| c.published = self.published; c.save}
end
end
83. Simple
Transaction
class Order
belongs_to :user
after_create :mark_user_as_customer
def mark_user_as_customer
user.customer = true
user.save
end
end
84. What happened
to
my transaction?
> order = Order.first
=> #<Order id: 1, user_id: 1>
> order.user.customer?
=> false
> order.user?
=> #<User id: 1, login: "marcos", customer: false>