From 12559b01eae408c0f3e820ef9c6bc6e356ab889a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 22 Mar 2016 21:38:47 +0100 Subject: [PATCH] Add pagination by max_id instead of offset/limit --- app/controllers/api/accounts_controller.rb | 2 +- app/controllers/api/statuses_controller.rb | 4 ++-- app/models/feed.rb | 6 +++--- app/models/status.rb | 5 +++-- app/services/fan_out_on_write_service.rb | 2 +- app/services/precompute_feed_service.rb | 2 +- lib/tasks/feeds.rake | 8 ++++++++ 7 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 lib/tasks/feeds.rake diff --git a/app/controllers/api/accounts_controller.rb b/app/controllers/api/accounts_controller.rb index f543ea98d9..5bac98f81a 100644 --- a/app/controllers/api/accounts_controller.rb +++ b/app/controllers/api/accounts_controller.rb @@ -15,7 +15,7 @@ class Api::AccountsController < ApiController end def statuses - @statuses = @account.statuses.with_includes.with_counters.order('created_at desc') + @statuses = @account.statuses.with_includes.with_counters.paginate_by_max_id(20, params[:max_id]) end def follow diff --git a/app/controllers/api/statuses_controller.rb b/app/controllers/api/statuses_controller.rb index 951f7113a1..ba216a7b33 100644 --- a/app/controllers/api/statuses_controller.rb +++ b/app/controllers/api/statuses_controller.rb @@ -23,11 +23,11 @@ class Api::StatusesController < ApiController def home feed = Feed.new(:home, current_user.account) - @statuses = feed.get(20, (params[:offset] || 0).to_i) + @statuses = feed.get(20, params[:max_id] || '+inf') end def mentions feed = Feed.new(:mentions, current_user.account) - @statuses = feed.get(20, (params[:offset] || 0).to_i) + @statuses = feed.get(20, params[:max_id] || '+inf') end end diff --git a/app/models/feed.rb b/app/models/feed.rb index 9f2b34c82d..206f287e7d 100644 --- a/app/models/feed.rb +++ b/app/models/feed.rb @@ -4,12 +4,12 @@ class Feed @account = account end - def get(limit, offset = 0) - unhydrated = redis.zrevrange(key, offset, limit) + def get(limit, max_id = '+inf') + unhydrated = redis.zrevrangebyscore(key, "(#{max_id}", '-inf', limit: [0, limit]) status_map = Hash.new # If we're after most recent items and none are there, we need to precompute the feed - return PrecomputeFeedService.new.(@type, @account).take(limit) if unhydrated.empty? && offset == 0 + return PrecomputeFeedService.new.(@type, @account).take(limit) if unhydrated.empty? && max_id == '+inf' Status.where(id: unhydrated).with_includes.with_counters.each { |status| status_map[status.id.to_s] = status } return unhydrated.map { |id| status_map[id] }.compact diff --git a/app/models/status.rb b/app/models/status.rb index 58d25546c7..f1c12383b6 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -15,8 +15,9 @@ class Status < ActiveRecord::Base validates :uri, uniqueness: true, unless: 'local?' validates :text, presence: true, if: Proc.new { |s| s.local? && !s.reblog? } - scope :with_counters, -> { select('statuses.*, (select count(r.id) from statuses as r where r.reblog_of_id = statuses.id) as reblogs_count, (select count(f.id) from favourites as f where f.status_id = statuses.id) as favourites_count') } - scope :with_includes, -> { includes(:account, reblog: :account, thread: :account) } + scope :with_counters, -> { select('statuses.*, (select count(r.id) from statuses as r where r.reblog_of_id = statuses.id) as reblogs_count, (select count(f.id) from favourites as f where f.status_id = statuses.id) as favourites_count') } + scope :with_includes, -> { includes(:account, reblog: :account, thread: :account) } + scope :paginate_by_max_id, -> (limit, max_id) { order('id desc').limit(limit).where('id < ?', max_id) } def local? self.uri.nil? diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb index 45814cfb5c..62cf2a1fea 100644 --- a/app/services/fan_out_on_write_service.rb +++ b/app/services/fan_out_on_write_service.rb @@ -31,7 +31,7 @@ class FanOutOnWriteService < BaseService end def push(type, receiver_id, status) - redis.zadd(key(type, receiver_id), status.created_at.to_i, status.id) + redis.zadd(key(type, receiver_id), status.id, status.id) trim(type, receiver_id) end diff --git a/app/services/precompute_feed_service.rb b/app/services/precompute_feed_service.rb index 0fb33db235..9d3b8d370e 100644 --- a/app/services/precompute_feed_service.rb +++ b/app/services/precompute_feed_service.rb @@ -14,7 +14,7 @@ class PrecomputeFeedService < BaseService private def push(type, receiver_id, status) - redis.zadd(key(type, receiver_id), status.created_at.to_i, status.id) + redis.zadd(key(type, receiver_id), status.id, status.id) end def home(account) diff --git a/lib/tasks/feeds.rake b/lib/tasks/feeds.rake new file mode 100644 index 0000000000..8f4dc78b98 --- /dev/null +++ b/lib/tasks/feeds.rake @@ -0,0 +1,8 @@ +namespace :feeds do + + desc "Removes all feeds from Redis, forcing a precompute on next request for each user" + task clear: :environment do + $redis.keys('feed:*').each { |key| $redis.del(key) } + end + +end