FIX: hot not adding recently bumped topics (#25619)

When we insert into the hot set we add things with a score of 0
This means that if hot has more than batch size items in it with a score, then the 0s don't get an initial score

This corrects the situation by always ensuring we re-score:

1. batch size high scoring topics
2. (new) batch size recently bumped topics

* Update spec/models/topic_hot_scores_spec.rb

Co-authored-by: Isaac Janzen <50783505+janzenisaac@users.noreply.github.com>

---------

Co-authored-by: Isaac Janzen <50783505+janzenisaac@users.noreply.github.com>
This commit is contained in:
Sam 2024-02-09 07:45:47 +11:00 committed by GitHub
parent c9b9463ee3
commit c8410537c1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 45 additions and 6 deletions

View File

@ -102,9 +102,26 @@ class TopicHotScore < ActiveRecord::Base
WHERE thsOrig.topic_id = ths.topic_id
SQL
# update up to BATCH_SIZE records that are out of date based on age
# we need an extra index for this
DB.exec(<<~SQL, args)
# we may end up update 2x batch size, this is ok
# we need to update 1 batch of high scoring topics
# we need to update a second batch of recently bumped topics
sql = <<~SQL
WITH topic_ids AS (
SELECT topic_id FROM (
SELECT th3.topic_id FROM topic_hot_scores th3
JOIN topics t3 on t3.id = th3.topic_id
ORDER BY t3.bumped_at DESC
LIMIT :max
) Y
UNION ALL
SELECT topic_id FROM (
SELECT th2.topic_id FROM topic_hot_scores th2
ORDER BY th2.score DESC, th2.recent_first_bumped_at DESC NULLS LAST
LIMIT :max
) X
)
UPDATE topic_hot_scores ths
SET score = (
CASE WHEN topics.created_at > :recent_cutoff
@ -121,11 +138,11 @@ class TopicHotScore < ActiveRecord::Base
FROM topics
WHERE topics.id IN (
SELECT topic_id FROM topic_hot_scores
ORDER BY score DESC, recent_first_bumped_at DESC NULLS LAST
LIMIT :max
SELECT topic_id FROM topic_ids
) AND ths.topic_id = topics.id
SQL
DB.exec(sql, args)
end
end

View File

@ -6,6 +6,28 @@ RSpec.describe TopicHotScore do
fab!(:user2) { Fabricate(:user) }
fab!(:user3) { Fabricate(:user) }
it "also always updates based on recent activity" do
freeze_time
# this will come in with a score
topic = Fabricate(:topic, created_at: 1.hour.ago, bumped_at: 2.minutes.ago)
post = Fabricate(:post, topic: topic, created_at: 2.minute.ago)
PostActionCreator.like(user, post)
TopicHotScore.update_scores
# this will come in in the batch in score 0
topic = Fabricate(:topic, created_at: 1.minute.ago, bumped_at: 1.minute.ago)
post = Fabricate(:post, topic: topic, created_at: 1.minute.ago)
PostActionCreator.like(user, post)
# batch size is 1 so if we do not do something special we only update
# the high score topic and skip new
TopicHotScore.update_scores(1)
expect(TopicHotScore.find_by(topic_id: topic.id).score).to be_within(0.001).of(0.861)
end
it "can correctly update like counts and post counts and account for activity" do
freeze_time