discourse/app/services/random_topic_selector.rb

87 lines
1.9 KiB
Ruby
Raw Normal View History

class RandomTopicSelector
BACKFILL_SIZE = 3000
BACKFILL_LOW_WATER_MARK = 500
2017-07-28 09:20:09 +08:00
def self.backfill(category = nil)
2017-09-08 09:54:13 +08:00
exclude = category&.topic_id
# don't leak private categories into the "everything" group
user = category ? CategoryFeaturedTopic.fake_admin : nil
options = {
per_page: category ? category.num_featured_topics : 3,
visible: true,
no_definitions: true
}
options[:except_topic_ids] = [category.topic_id] if exclude
options[:category] = category.id if category
query = TopicQuery.new(user, options)
results = query.latest_results.order('RANDOM()')
2017-07-28 09:20:09 +08:00
.where(closed: false, archived: false)
.where("topics.created_at > ?", SiteSetting.suggested_topics_max_days_old.days.ago)
.limit(BACKFILL_SIZE)
.reorder('RANDOM()')
.pluck(:id)
key = cache_key(category)
2017-09-08 09:54:13 +08:00
if results.present?
$redis.multi do
$redis.rpush(key, results)
$redis.expire(key, 2.days)
end
end
results
end
2017-07-28 09:20:09 +08:00
def self.next(count, category = nil)
key = cache_key(category)
results = []
return results if count < 1
results = $redis.multi do
2017-07-28 09:20:09 +08:00
$redis.lrange(key, 0, count - 1)
$redis.ltrim(key, count, -1)
end
if !results.is_a?(Array) # Redis is in readonly mode
2017-07-28 09:20:09 +08:00
results = $redis.lrange(key, 0, count - 1)
else
results = results[0]
end
results.map!(&:to_i)
left = count - results.length
backfilled = false
if left > 0
ids = backfill(category)
backfilled = true
results += ids[0...count]
results.uniq!
results = results[0...count]
end
if !backfilled && $redis.llen(key) < BACKFILL_LOW_WATER_MARK
Scheduler::Defer.later("backfill") do
backfill(category)
end
end
results
end
2017-07-28 09:20:09 +08:00
def self.cache_key(category = nil)
2017-09-08 09:54:13 +08:00
"random_topic_cache_#{category&.id}"
end
end