def increment_count!(key)
update(attributes_for_increment(key))
- rescue ActiveRecord::StaleObjectError
+ rescue ActiveRecord::StaleObjectError, ActiveRecord::RecordNotUnique
begin
reload_with_id
rescue ActiveRecord::RecordNotFound
- # Nothing to do
- else
- retry
+ return
end
+
+ retry
end
def decrement_count!(key)
- update(key => [public_send(key) - 1, 0].max)
- rescue ActiveRecord::StaleObjectError
+ update(attributes_for_decrement(key))
+ rescue ActiveRecord::StaleObjectError, ActiveRecord::RecordNotUnique
begin
reload_with_id
rescue ActiveRecord::RecordNotFound
- # Nothing to do
- else
- retry
+ return
end
+
+ retry
end
private
attrs
end
+ def attributes_for_decrement(key)
+ attrs = { key => [public_send(key) - 1, 0].max }
+ attrs
+ end
+
def reload_with_id
- self.id = find_by!(account: account).id if new_record?
+ self.id = self.class.find_by!(account: account).id if new_record?
reload
end
end
include_examples 'AccountAvatar', :account
include_examples 'AccountHeader', :account
+
+ describe '#increment_count!' do
+ subject { Fabricate(:account) }
+
+ it 'increments the count in multi-threaded an environment when account_stat is not yet initialized' do
+ subject
+
+ increment_by = 15
+ wait_for_start = true
+
+ threads = Array.new(increment_by) do
+ Thread.new do
+ true while wait_for_start
+ Account.find(subject.id).increment_count!(:followers_count)
+ end
+ end
+
+ wait_for_start = false
+ threads.each(&:join)
+
+ expect(subject.reload.followers_count).to eq 15
+ end
+ end
end