timeout when doing possibly unnecessary complicated counts for pagination
fixes USERS-274 test plan: * have a lot of users in an account (like 500) * go to /accounts/self/users * it should load, and show you how many pages there are * set the timeout to something absurdly low (like Setting.set('pagination_count_timeout', '1ms')) * go to the page again * it should still load the first page quickly, but the pages thingy at the bottom should only list 1 and 2, and then an ellipsis Change-Id: Ibc07036b39a9f4ed19d8824bb9254b23679298d1 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/234557 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Simon Williams <simon@instructure.com> QA-Review: Cody Cutrer <cody@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
This commit is contained in:
parent
cd27ce2ce9
commit
c8b0c29361
|
@ -15,4 +15,44 @@
|
|||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
require 'folio/core_ext/enumerable'
|
||||
require 'folio/core_ext/enumerable'
|
||||
|
||||
module Folio::WillPaginate::ActiveRecord::Pagination
|
||||
def paginate(options={})
|
||||
if !options.has_key?(:total_entries)
|
||||
scope = if ::Rails.version < '4'
|
||||
self.scoped
|
||||
elsif self.is_a?(::ActiveRecord::Relation)
|
||||
self
|
||||
elsif self < ::ActiveRecord::Base
|
||||
self.all
|
||||
else
|
||||
self.scope
|
||||
end
|
||||
begin
|
||||
scope.connection.transaction(requires_new: true) do
|
||||
scope.connection.execute("SET LOCAL statement_timeout='#{Setting.get('pagination_count_timeout', '5s')}'")
|
||||
group_values = scope.group_values
|
||||
unless group_values.empty?
|
||||
# total_entries left to an auto-count, but the relation being
|
||||
# paginated has a grouping. we need to do a special count, lest
|
||||
# self.count give us a hash instead of the integer we expect.
|
||||
having_clause_empty = Rails.version < '5' ? scope.having_values.empty? : scope.having_clause.empty?
|
||||
if having_clause_empty && group_values.length == 1 # multi-column distinct counts are broken right now (as of rails 4.2.5) :(
|
||||
if Rails.version < '5'
|
||||
options[:total_entries] = except(:group, :select).select(group_values).uniq.count
|
||||
else
|
||||
options[:total_entries] = except(:group, :select).select(group_values).distinct.count
|
||||
end
|
||||
else
|
||||
options[:total_entries] = unscoped.from("(#{to_sql}) a").count
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue ActiveRecord::QueryCanceled
|
||||
options[:total_entries] = nil
|
||||
end
|
||||
end
|
||||
super(options).to_a
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
#
|
||||
# Copyright (C) 2020 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
require_relative '../spec_helper'
|
||||
|
||||
describe Folio do
|
||||
it "skips the count for a grouped query that takes a long time" do
|
||||
User.create!
|
||||
User.create!
|
||||
Setting.set('pagination_count_timeout', '5ms')
|
||||
result = User.group(:id).where("pg_sleep(0.1) IS NOT NULL").paginate(per_page: 1)
|
||||
expect(result.length).to eq 1
|
||||
expect(result.total_entries).to be_nil
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue