forked from cybrespace/mastodon
62 lines
1.7 KiB
Ruby
62 lines
1.7 KiB
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
class Scheduler::FollowRecommendationsScheduler
|
||
|
include Sidekiq::Worker
|
||
|
include Redisable
|
||
|
|
||
|
sidekiq_options retry: 0
|
||
|
|
||
|
# The maximum number of accounts that can be requested in one page from the
|
||
|
# API is 80, and the suggestions API does not allow pagination. This number
|
||
|
# leaves some room for accounts being filtered during live access
|
||
|
SET_SIZE = 100
|
||
|
|
||
|
def perform
|
||
|
# Maintaining a materialized view speeds-up subsequent queries significantly
|
||
|
AccountSummary.refresh
|
||
|
|
||
|
fallback_recommendations = FollowRecommendation.safe.filtered.limit(SET_SIZE).index_by(&:account_id)
|
||
|
|
||
|
I18n.available_locales.each do |locale|
|
||
|
recommendations = begin
|
||
|
if AccountSummary.safe.filtered.localized(locale).exists? # We can skip the work if no accounts with that language exist
|
||
|
FollowRecommendation.safe.filtered.localized(locale).limit(SET_SIZE).index_by(&:account_id)
|
||
|
else
|
||
|
{}
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# Use language-agnostic results if there are not enough language-specific ones
|
||
|
missing = SET_SIZE - recommendations.keys.size
|
||
|
|
||
|
if missing.positive?
|
||
|
added = 0
|
||
|
|
||
|
# Avoid duplicate results
|
||
|
fallback_recommendations.each_value do |recommendation|
|
||
|
next if recommendations.key?(recommendation.account_id)
|
||
|
|
||
|
recommendations[recommendation.account_id] = recommendation
|
||
|
added += 1
|
||
|
|
||
|
break if added >= missing
|
||
|
end
|
||
|
end
|
||
|
|
||
|
redis.pipelined do
|
||
|
redis.del(key(locale))
|
||
|
|
||
|
recommendations.each_value do |recommendation|
|
||
|
redis.zadd(key(locale), recommendation.rank, recommendation.account_id)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
private
|
||
|
|
||
|
def key(locale)
|
||
|
"follow_recommendations:#{locale}"
|
||
|
end
|
||
|
end
|