forked from treehouse/mastodon
Fix updating account counters when account_stat is not yet created (#15108)
parent
2b63c62c57
commit
337dc6e0ad
app/models
spec/models
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue