From cd22b6158c26abf14048a69defdbfa719695524d Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Aug 2014 14:20:42 +1000 Subject: [PATCH] PERF: stop mucking with user stats every 15 minutes (pushed to twice daily) --- app/jobs/scheduled/ensure_db_consistency.rb | 2 ++ app/jobs/scheduled/periodical_updates.rb | 3 --- app/models/post_timing.rb | 4 +++- app/models/topic_view_item.rb | 1 + app/models/user_stat.rb | 6 +++--- spec/models/post_timing_spec.rb | 22 +++++++-------------- spec/models/topic_view_item_spec.rb | 10 ++++++++++ 7 files changed, 26 insertions(+), 22 deletions(-) diff --git a/app/jobs/scheduled/ensure_db_consistency.rb b/app/jobs/scheduled/ensure_db_consistency.rb index e12c404cb3a..c4e940f81cc 100644 --- a/app/jobs/scheduled/ensure_db_consistency.rb +++ b/app/jobs/scheduled/ensure_db_consistency.rb @@ -10,6 +10,8 @@ module Jobs Notification.ensure_consistency! UserAction.ensure_consistency! UserBadge.ensure_consistency! + # ensure consistent + UserStat.update_view_counts(13.hours.ago) end end end diff --git a/app/jobs/scheduled/periodical_updates.rb b/app/jobs/scheduled/periodical_updates.rb index f1c27def157..60fdf0aa9ab 100644 --- a/app/jobs/scheduled/periodical_updates.rb +++ b/app/jobs/scheduled/periodical_updates.rb @@ -12,9 +12,6 @@ module Jobs # Feature topics in categories CategoryFeaturedTopic.feature_topics - # Update view counts for users - UserStat.update_view_counts - # Update the scores of posts ScoreCalculator.new.calculate(1.day.ago) diff --git a/app/models/post_timing.rb b/app/models/post_timing.rb index 1f6c070d0e9..245f512c6a9 100644 --- a/app/models/post_timing.rb +++ b/app/models/post_timing.rb @@ -39,7 +39,7 @@ class PostTiming < ActiveRecord::Base args) if rows == 0 - Post.where(['topic_id = :topic_id and post_number = :post_number', args]).update_all 'reads = reads + 1' + exec_sql("INSERT INTO post_timings (topic_id, user_id, post_number, msecs) SELECT :topic_id, :user_id, :post_number, :msecs WHERE NOT EXISTS(SELECT 1 FROM post_timings @@ -48,6 +48,8 @@ class PostTiming < ActiveRecord::Base AND post_number = :post_number)", args) + Post.where(['topic_id = :topic_id and post_number = :post_number', args]).update_all 'reads = reads + 1' + UserStat.where(user_id: args[:user_id]).update_all 'posts_read_count = posts_read_count + 1' end end diff --git a/app/models/topic_view_item.rb b/app/models/topic_view_item.rb index bd2d1545127..ecb659cc6a9 100644 --- a/app/models/topic_view_item.rb +++ b/app/models/topic_view_item.rb @@ -42,6 +42,7 @@ class TopicViewItem < ActiveRecord::Base if result.cmd_tuples > 0 Topic.where(id: topic_id).update_all 'views = views + 1' + UserStat.where(user_id: user_id).update_all 'topics_entered = topics_entered + 1' if user_id end # Update the views count in the parent, if it exists. diff --git a/app/models/user_stat.rb b/app/models/user_stat.rb index df032ab90e0..3eb8ab98196 100644 --- a/app/models/user_stat.rb +++ b/app/models/user_stat.rb @@ -4,7 +4,7 @@ class UserStat < ActiveRecord::Base after_save :trigger_badges # Updates the denormalized view counts for all users - def self.update_view_counts + def self.update_view_counts(last_seen = 1.hour.ago) # NOTE: we only update the counts for users we have seen in the last hour # this avoids a very expensive query that may run on the entire user base @@ -22,7 +22,7 @@ class UserStat < ActiveRecord::Base WHERE X.user_id = user_stats.user_id AND X.c <> topics_entered - ", seen_at: 1.hour.ago + ", seen_at: last_seen # Update denormalzied posts_read_count exec_sql "UPDATE user_stats SET posts_read_count = X.c @@ -35,7 +35,7 @@ class UserStat < ActiveRecord::Base GROUP BY pt.user_id) AS X WHERE X.user_id = user_stats.user_id AND X.c <> posts_read_count - ", seen_at: 1.hour.ago + ", seen_at: last_seen end def update_topic_reply_count diff --git a/spec/models/post_timing_spec.rb b/spec/models/post_timing_spec.rb index 08153439505..3cdedc9ca3e 100644 --- a/spec/models/post_timing_spec.rb +++ b/spec/models/post_timing_spec.rb @@ -93,12 +93,6 @@ describe PostTiming do @timing_attrs = {msecs: 1234, topic_id: @post.topic_id, user_id: @coding_horror.id, post_number: @post.post_number} end - it 'creates a post timing record' do - lambda { - PostTiming.record_timing(@timing_attrs) - }.should change(PostTiming, :count).by(1) - end - it 'adds a view to the post' do lambda { PostTiming.record_timing(@timing_attrs) @@ -107,19 +101,17 @@ describe PostTiming do end describe 'multiple calls' do - before do + it 'correctly works' do PostTiming.record_timing(@timing_attrs) PostTiming.record_timing(@timing_attrs) - @timing = PostTiming.find_by(topic_id: @post.topic_id, user_id: @coding_horror.id, post_number: @post.post_number) + timing = PostTiming.find_by(topic_id: @post.topic_id, user_id: @coding_horror.id, post_number: @post.post_number) + + timing.should be_present + timing.msecs.should == 2468 + + @coding_horror.user_stat.posts_read_count.should == 1 end - it 'creates a timing record' do - @timing.should be_present - end - - it 'sums the msecs together' do - @timing.msecs.should == 2468 - end end describe 'avg times' do diff --git a/spec/models/topic_view_item_spec.rb b/spec/models/topic_view_item_spec.rb index 14c980f9a57..c2aa1ccc75e 100644 --- a/spec/models/topic_view_item_spec.rb +++ b/spec/models/topic_view_item_spec.rb @@ -17,4 +17,14 @@ describe TopicViewItem do TopicViewItem.count.should == 3 end + it "increases a users view count" do + user = Fabricate(:user) + + add(1, "1.1.1.1", user.id) + add(1, "1.1.1.1", user.id) + + user.user_stat.reload + user.user_stat.topics_entered.should == 1 + end + end