diff --git a/config/environments/development.rb b/config/environments/development.rb index 33d9e12cf4ab87b7a9bbe5baefeea0009e88e4b6..7f3a6aaa681f23a413aa4574bfc10d5dcdf30d5f 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -21,9 +21,6 @@ config.action_controller.perform_caching = false end - # Show a warning when a large data set is loaded into memory - config.active_record.warn_on_records_fetched_greater_than = 1000 - # Raise an error on page load if there are pending migrations config.active_record.migration_error = :page_load diff --git a/config/initializers/record_count_monitor.rb b/config/initializers/record_count_monitor.rb new file mode 100644 index 0000000000000000000000000000000000000000..19e345fff4dea98ab6ed044fdbe4738bb52fbb8a --- /dev/null +++ b/config/initializers/record_count_monitor.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +Gitlab::Database::RecordCountMonitor.subscribe if Rails.env.development? diff --git a/lib/gitlab/database/record_count_monitor.rb b/lib/gitlab/database/record_count_monitor.rb new file mode 100644 index 0000000000000000000000000000000000000000..1fefccb1ccfe7125e215afdb1dfe9be8b3be665c --- /dev/null +++ b/lib/gitlab/database/record_count_monitor.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Gitlab + module Database + class RecordCountMonitor + THRESHOLD = 1_000 + + def self.subscribe + return if @subscribed + + ActiveSupport::Notifications.subscribe('sql.active_record') do |event| + next unless event[:row_count] + next if event[:row_count] <= THRESHOLD + + warn_large_result_set(event) + end + + @subscribed = true + end + + def self.warn_large_result_set(event) + message = "Query fetched #{event[:row_count]} rows (threshold: #{THRESHOLD})" + message += "\nSQL: #{event[:sql]}" if event[:sql] + + Gitlab::AppLogger.warn(message) + end + end + end +end diff --git a/spec/lib/gitlab/database/record_count_monitor_spec.rb b/spec/lib/gitlab/database/record_count_monitor_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..b69e14f52d6b448dc22d7f180554eea40d8019bd --- /dev/null +++ b/spec/lib/gitlab/database/record_count_monitor_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Database::RecordCountMonitor, feature_category: :database do + describe '.subscribe' do + it 'subscribes to sql.active_record notifications' do + expect(ActiveSupport::Notifications).to receive(:subscribe).with('sql.active_record') + + described_class.subscribe + end + end + + describe '.warn_large_result_set' do + before do + allow(Gitlab::AppLogger).to receive(:warn) + end + + it 'logs warning with row count' do + described_class.warn_large_result_set({ row_count: 5000 }) + + expect(Gitlab::AppLogger).to have_received(:warn).with(/Query fetched 5000 rows/) + end + + it 'includes SQL when present' do + described_class.warn_large_result_set({ row_count: 5000, sql: 'SELECT * FROM users' }) + + expect(Gitlab::AppLogger).to have_received(:warn).with(/SELECT \* FROM users/) + end + + it 'does not include SQL when not present' do + described_class.warn_large_result_set({ row_count: 5000 }) + + expect(Gitlab::AppLogger).to have_received(:warn).with("Query fetched 5000 rows (threshold: 1000)") + end + end +end