about summary refs log tree commit diff
path: root/app/workers/scheduler/follow_recommendations_scheduler.rb
blob: cb1e1596179ac26cafaf9a5b3a738a20b6175feb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# 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
    FollowRecommendation.refresh

    fallback_recommendations = FollowRecommendation.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.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