diff --git a/app/services/search/base.rb b/app/services/search/base.rb index 2f63bde0d..30bfa79d7 100644 --- a/app/services/search/base.rb +++ b/app/services/search/base.rb @@ -33,10 +33,20 @@ module Search Search::Client.delete(id: doc_id, index: self::INDEX_ALIAS) end + def index_exists?(index_name: self::INDEX_NAME) + Search::Client.indices.exists(index: index_name) + end + def create_index(index_name: self::INDEX_NAME) Search::Client.indices.create(index: index_name, body: settings) end + def update_index(index_name: self::INDEX_NAME) + return unless dynamic_index_settings.any? + + Search::Client.indices.put_settings(index: index_name, body: dynamic_settings) + end + def delete_index(index_name: self::INDEX_NAME) Search::Client.indices.delete(index: index_name) end @@ -97,6 +107,14 @@ module Search raise "Search classes must implement their own index settings" end + def dynamic_settings + { settings: { index: dynamic_index_settings } } + end + + def dynamic_index_settings + {} + end + def process_hashes(indexing_hashes) indexing_hashes.in_groups_of(1000, false).flat_map do |hashes| indexing_chunks(hashes).select(&:any?).map { |chunk| Search::Client.bulk(body: chunk) } diff --git a/app/services/search/cluster.rb b/app/services/search/cluster.rb index 5ba71bb98..9aea2ea67 100644 --- a/app/services/search/cluster.rb +++ b/app/services/search/cluster.rb @@ -18,6 +18,7 @@ module Search def setup_indexes update_settings create_indexes + update_indexes add_aliases update_mappings end @@ -28,12 +29,16 @@ module Search def create_indexes SEARCH_CLASSES.each do |search_class| - next if Search::Client.indices.exists(index: search_class::INDEX_NAME) + next if search_class.index_exists? search_class.create_index end end + def update_indexes + SEARCH_CLASSES.each(&:update_index) + end + def add_aliases SEARCH_CLASSES.each(&:add_alias) end diff --git a/app/services/search/feed_content.rb b/app/services/search/feed_content.rb index d7568b412..f098202de 100644 --- a/app/services/search/feed_content.rb +++ b/app/services/search/feed_content.rb @@ -70,6 +70,14 @@ module Search } end end + + def dynamic_index_settings + if Rails.env.production? + { refresh_interval: "5s" } + else + { refresh_interval: "1s" } + end + end end end end diff --git a/app/services/search/reaction.rb b/app/services/search/reaction.rb index f95216569..e9748d80f 100644 --- a/app/services/search/reaction.rb +++ b/app/services/search/reaction.rb @@ -34,6 +34,14 @@ module Search } end end + + def dynamic_index_settings + if Rails.env.production? + { refresh_interval: "2s" } + else + { refresh_interval: "1s" } + end + end end end end diff --git a/app/services/search/user.rb b/app/services/search/user.rb index 10bb6ae01..c19c54990 100644 --- a/app/services/search/user.rb +++ b/app/services/search/user.rb @@ -42,6 +42,14 @@ module Search } end end + + def dynamic_index_settings + if Rails.env.production? + { refresh_interval: "10s" } + else + { refresh_interval: "1s" } + end + end end end end diff --git a/spec/services/search/base_spec.rb b/spec/services/search/base_spec.rb index 59f9549d0..47a971f8c 100644 --- a/spec/services/search/base_spec.rb +++ b/spec/services/search/base_spec.rb @@ -3,6 +3,13 @@ require "rails_helper" RSpec.describe Search::Base, type: :service do let(:document_id) { 123 } + def recreate_tag_index + Search::Tag.delete_index if described_class.index_exists? + Search::Tag.create_index + Search::Tag.add_alias + Search::Tag.update_mappings + end + before do # Need to use an existing index name to ensure proper data cleanup stub_const("#{described_class}::INDEX_NAME", "tags_#{Rails.env}") @@ -69,7 +76,11 @@ RSpec.describe Search::Base, type: :service do end end - describe "::create_index", elasticsearch_reset: true do + describe "::create_index" do + before { recreate_tag_index } + + after { recreate_tag_index } + it "creates an elasticsearch index with INDEX_NAME" do described_class.delete_index expect(Search::Client.indices.exists(index: described_class::INDEX_NAME)).to eq(false) @@ -88,7 +99,31 @@ RSpec.describe Search::Base, type: :service do end end - describe "::delete_index", elasticsearch_reset: true do + describe "::update_index" do + before do + recreate_tag_index + allow(described_class).to receive(:dynamic_index_settings).and_return( + refresh_interval: "10s", + ) + end + + after { recreate_tag_index } + + it "updates elasticsearch index settings with INDEX_NAME" do + index_info = Search::Client.indices.get(index: described_class::INDEX_NAME) + expect(index_info.values.first.dig("settings", "index", "refresh_interval")).to be_nil + described_class.update_index + + new_index_info = Search::Client.indices.get(index: described_class::INDEX_NAME) + expect(new_index_info.values.first.dig("settings", "index", "refresh_interval")).to eq("10s") + end + end + + describe "::delete_index" do + before { recreate_tag_index } + + after { recreate_tag_index } + it "deletes an elasticsearch index with INDEX_NAME" do expect(Search::Client.indices.exists(index: described_class::INDEX_NAME)).to eq(true) described_class.delete_index diff --git a/spec/services/search/cluster_spec.rb b/spec/services/search/cluster_spec.rb index 02299ee31..6ae6433b4 100644 --- a/spec/services/search/cluster_spec.rb +++ b/spec/services/search/cluster_spec.rb @@ -36,6 +36,16 @@ RSpec.describe Search::Cluster, type: :service do end end + describe "::update_indexes" do + it "calls update_index for each search class" do + described_class::SEARCH_CLASSES.each do |search_class| + allow(search_class).to receive(:update_index) + end + described_class.update_indexes + expect(described_class::SEARCH_CLASSES).to all(have_received(:update_index)) + end + end + describe "::delete_indexes" do it "calls delete_index for each search class" do allow(Search::Client.indices).to receive(:exists).and_return(true)