Fix updating account counters when account_stat is not yet created (#15108)

This commit is contained in:
Eugen Rochko 2020-11-09 16:00:23 +01:00 committed by GitHub
parent 2b63c62c57
commit 337dc6e0ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 10 deletions

View File

@ -21,26 +21,26 @@ class AccountStat < ApplicationRecord
def increment_count!(key) def increment_count!(key)
update(attributes_for_increment(key)) update(attributes_for_increment(key))
rescue ActiveRecord::StaleObjectError rescue ActiveRecord::StaleObjectError, ActiveRecord::RecordNotUnique
begin begin
reload_with_id reload_with_id
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
# Nothing to do return
else
retry
end end
retry
end end
def decrement_count!(key) def decrement_count!(key)
update(key => [public_send(key) - 1, 0].max) update(attributes_for_decrement(key))
rescue ActiveRecord::StaleObjectError rescue ActiveRecord::StaleObjectError, ActiveRecord::RecordNotUnique
begin begin
reload_with_id reload_with_id
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
# Nothing to do return
else
retry
end end
retry
end end
private private
@ -51,8 +51,13 @@ class AccountStat < ApplicationRecord
attrs attrs
end end
def attributes_for_decrement(key)
attrs = { key => [public_send(key) - 1, 0].max }
attrs
end
def reload_with_id 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 reload
end end
end end

View File

@ -817,4 +817,27 @@ RSpec.describe Account, type: :model do
include_examples 'AccountAvatar', :account include_examples 'AccountAvatar', :account
include_examples 'AccountHeader', :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 end