Specs for precompute feed service (#3142)
* Add spec for precompute feed service * Refactor PrecomputeFeedService * spec wip
This commit is contained in:
		
					parent
					
						
							
								4a3db71692
							
						
					
				
			
			
				commit
				
					
						db4119f971
					
				
			
		
					 3 changed files with 57 additions and 10 deletions
				
			
		|  | @ -1,20 +1,48 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class PrecomputeFeedService < BaseService | ||||
|   # Fill up a user's home/mentions feed from DB and return a subset | ||||
|   # @param [Symbol] type :home or :mentions | ||||
|   # @param [Account] account | ||||
|   def call(_, account) | ||||
|   LIMIT = FeedManager::MAX_ITEMS / 4 | ||||
| 
 | ||||
|   def call(account) | ||||
|     @account = account | ||||
|     populate_feed | ||||
|   end | ||||
| 
 | ||||
|   private | ||||
| 
 | ||||
|   attr_reader :account | ||||
| 
 | ||||
|   def populate_feed | ||||
|     redis.pipelined do | ||||
|       # NOTE: Added `id desc, account_id desc` to `ORDER BY` section to optimize query. | ||||
|       Status.as_home_timeline(account).order(account_id: :desc).limit(FeedManager::MAX_ITEMS / 4).each do |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) | ||||
|       statuses.each do |status| | ||||
|         process_status(status) | ||||
|       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 | ||||
|     Redis.current | ||||
|  |  | |||
|  | @ -6,6 +6,8 @@ class RegenerationWorker | |||
|   sidekiq_options queue: 'pull', backtrace: true, unique: :until_executed | ||||
| 
 | ||||
|   def perform(account_id, _ = :home) | ||||
|     PrecomputeFeedService.new.call(:home, Account.find(account_id)) | ||||
|     account = Account.find(account_id) | ||||
| 
 | ||||
|     PrecomputeFeedService.new.call(account) | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -1,5 +1,22 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| require 'rails_helper' | ||||
| 
 | ||||
| RSpec.describe PrecomputeFeedService do | ||||
|   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 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue