Do not push status to feed if its reblog is already inserted (#6488)

A complemental change for precompute_feed_service_spec.rb also fixes its
random failure which is caused by the Snowlake randomization of the order
of an original status and its reblog.
th-downstream
Akihiko Odaki 7 years ago committed by Eugen Rochko
parent d1806f5dc4
commit 7ac6e09dde

@ -220,6 +220,14 @@ class FeedManager
return false return false
end end
else else
# A reblog may reach earlier than the original status because of the
# delay of the worker deliverying the original status, the late addition
# by merging timelines, and other reasons.
# If such a reblog already exists, just do not re-insert it into the feed.
rank = redis.zrevrank(reblog_key, status.id)
return false unless rank.nil?
redis.zadd(timeline_key, status.id, status.id) redis.zadd(timeline_key, status.id, status.id)
end end

@ -1,4 +1,4 @@
Fabricator(:list) do Fabricator(:list) do
account nil account
title "MyString" title "MyString"
end end

@ -157,7 +157,7 @@ RSpec.describe FeedManager do
end end
end end
describe '#push' do describe '#push_to_home' do
it 'trims timelines if they will have more than FeedManager::MAX_ITEMS' do it 'trims timelines if they will have more than FeedManager::MAX_ITEMS' do
account = Fabricate(:account) account = Fabricate(:account)
status = Fabricate(:status) status = Fabricate(:status)
@ -248,6 +248,39 @@ RSpec.describe FeedManager do
expect(FeedManager.instance.push_to_home(account, reblogs.last)).to be true expect(FeedManager.instance.push_to_home(account, reblogs.last)).to be true
end end
end end
it "does not push when the given status's reblog is already inserted" do
account = Fabricate(:account)
reblog = Fabricate(:status)
status = Fabricate(:status, reblog: reblog)
FeedManager.instance.push_to_home(account, status)
expect(FeedManager.instance.push_to_home(account, reblog)).to eq false
end
end
describe '#push_to_list' do
it "does not push when the given status's reblog is already inserted" do
list = Fabricate(:list)
reblog = Fabricate(:status)
status = Fabricate(:status, reblog: reblog)
FeedManager.instance.push_to_list(list, status)
expect(FeedManager.instance.push_to_list(list, reblog)).to eq false
end
end
describe '#merge_into_timeline' do
it "does not push source account's statuses whose reblogs are already inserted" do
account = Fabricate(:account, id: 0)
reblog = Fabricate(:status)
status = Fabricate(:status, reblog: reblog)
FeedManager.instance.push_to_home(account, status)
FeedManager.instance.merge_into_timeline(account, reblog.account)
expect(Redis.current.zscore("feed:home:0", reblog.id)).to eq nil
end
end end
describe '#trim' do describe '#trim' do

@ -9,14 +9,11 @@ RSpec.describe PrecomputeFeedService do
let(:account) { Fabricate(:account) } let(:account) { Fabricate(:account) }
it 'fills a user timeline with statuses' do it 'fills a user timeline with statuses' do
account = Fabricate(:account) account = Fabricate(:account)
followed_account = Fabricate(:account) status = Fabricate(:status, account: account)
Fabricate(:follow, account: account, target_account: followed_account)
reblog = Fabricate(:status, account: followed_account)
status = Fabricate(:status, account: account, reblog: reblog)
subject.call(account) subject.call(account)
expect(Redis.current.zscore(FeedManager.instance.key(:home, account.id), reblog.id)).to be_within(0.1).of(status.id.to_f) expect(Redis.current.zscore(FeedManager.instance.key(:home, account.id), status.id)).to be_within(0.1).of(status.id.to_f)
end end
it 'does not raise an error even if it could not find any status' do it 'does not raise an error even if it could not find any status' do

Loading…
Cancel
Save