forked from treehouse/mastodon
Specs for precompute feed service (#3142)
* Add spec for precompute feed service * Refactor PrecomputeFeedService * spec wipsignup-info-prompt
parent
4a3db71692
commit
db4119f971
|
@ -1,20 +1,48 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class PrecomputeFeedService < BaseService
|
class PrecomputeFeedService < BaseService
|
||||||
# Fill up a user's home/mentions feed from DB and return a subset
|
LIMIT = FeedManager::MAX_ITEMS / 4
|
||||||
# @param [Symbol] type :home or :mentions
|
|
||||||
# @param [Account] account
|
def call(account)
|
||||||
def call(_, account)
|
@account = account
|
||||||
|
populate_feed
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
attr_reader :account
|
||||||
|
|
||||||
|
def populate_feed
|
||||||
redis.pipelined do
|
redis.pipelined do
|
||||||
# NOTE: Added `id desc, account_id desc` to `ORDER BY` section to optimize query.
|
statuses.each do |status|
|
||||||
Status.as_home_timeline(account).order(account_id: :desc).limit(FeedManager::MAX_ITEMS / 4).each do |status|
|
process_status(status)
|
||||||
next if status.direct_visibility? || FeedManager.instance.filter?(:home, status, account.id)
|
|
||||||
redis.zadd(FeedManager.instance.key(:home, account.id), status.id, status.reblog? ? status.reblog_of_id : status.id)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
def process_status(status)
|
||||||
|
add_status_to_feed(status) unless skip_status?(status)
|
||||||
|
end
|
||||||
|
|
||||||
|
def skip_status?(status)
|
||||||
|
status.direct_visibility? || status_filtered?(status)
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_status_to_feed(status)
|
||||||
|
redis.zadd(account_home_key, status.id, status.reblog? ? status.reblog_of_id : status.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def status_filtered?(status)
|
||||||
|
FeedManager.instance.filter?(:home, status, account.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def account_home_key
|
||||||
|
FeedManager.instance.key(:home, account.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def statuses
|
||||||
|
Status.as_home_timeline(account).order(account_id: :desc).limit(LIMIT)
|
||||||
|
end
|
||||||
|
|
||||||
def redis
|
def redis
|
||||||
Redis.current
|
Redis.current
|
||||||
|
|
|
@ -6,6 +6,8 @@ class RegenerationWorker
|
||||||
sidekiq_options queue: 'pull', backtrace: true, unique: :until_executed
|
sidekiq_options queue: 'pull', backtrace: true, unique: :until_executed
|
||||||
|
|
||||||
def perform(account_id, _ = :home)
|
def perform(account_id, _ = :home)
|
||||||
PrecomputeFeedService.new.call(:home, Account.find(account_id))
|
account = Account.find(account_id)
|
||||||
|
|
||||||
|
PrecomputeFeedService.new.call(account)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe PrecomputeFeedService do
|
RSpec.describe PrecomputeFeedService do
|
||||||
subject { PrecomputeFeedService.new }
|
subject { PrecomputeFeedService.new }
|
||||||
|
|
||||||
|
describe 'call' do
|
||||||
|
let(:account) { Fabricate(:account) }
|
||||||
|
it 'fills a user timeline with statuses' do
|
||||||
|
account = Fabricate(:account)
|
||||||
|
followed_account = Fabricate(:account)
|
||||||
|
Fabricate(:follow, account: account, target_account: followed_account)
|
||||||
|
status = Fabricate(:status, account: followed_account)
|
||||||
|
|
||||||
|
expected_redis_args = FeedManager.instance.key(:home, account.id), status.id, status.id
|
||||||
|
expect_any_instance_of(Redis).to receive(:zadd).with(*expected_redis_args)
|
||||||
|
|
||||||
|
subject.call(account)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue