• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pulibrary / pdc_discovery / 5d558bd5-b403-4644-b5a9-148390098066

25 Jul 2025 07:29PM UTC coverage: 97.006% (-0.03%) from 97.038%
5d558bd5-b403-4644-b5a9-148390098066

push

circleci

web-flow
Log exceptions when indexing (#816)

2 of 3 new or added lines in 1 file covered. (66.67%)

2916 of 3006 relevant lines covered (97.01%)

115.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.43
/app/lib/indexing/solr_cloud_helper.rb
1
# frozen_string_literal: true
2
module Indexing
1✔
3
  class SolrCloudHelper
1✔
4
    def self.alias_uri
1✔
5
      Blacklight.default_index.connection.uri
1,784✔
6
    end
7

8
    def self.alias_url
1✔
9
      Blacklight.default_index.connection.uri.to_s
×
10
    end
11

12
    def self.config_set
1✔
13
      Blacklight.default_index.connection.options[:solr_config_set]
1,785✔
14
    end
15

16
    def self.collection_writer_commit!
1✔
17
      commit_url = "#{collection_writer_url}/update?commit=true"
1✔
18
      HTTParty.get(commit_url)
1✔
19
    end
20

21
    # Returns the Solr collection that we should use for quering data
22
    def self.collection_reader_url
1✔
23
      collection = current_collection_for_alias(alias_uri)
1✔
24
      build_solr_url_for_collection(alias_uri, collection)
1✔
25
    end
26

27
    # Returns the Solr collection that we should write to
28
    # (creates it if does not exist)
29
    def self.collection_writer_url
1✔
30
      collection_writer_for_alias(alias_uri, false)
1,782✔
31
    end
32

33
    # Returns the Solr collection that we should write to
34
    # (creates it if does not exists, deletes & recreates it if already exists)
35
    def self.create_collection_writer
1✔
36
      collection_writer_for_alias(alias_uri, true)
×
37
    end
38

39
    # For a given Solr alias, returns a URL that is suitable for writing new data without affecting
40
    # the existing Solr index. It does this by creating a new alternate Solr collection to write data,
41
    # instead of overwriting the data on the collection used by the provided solr_alias_uri.
42
    #
43
    # The code is hardcoded to toggle between collections "xxx-1 and "xxx-2".
44
    #
45
    # For example, if the provided solr_alias_uri is "http://server/solr/pdc-discovery-staging"
46
    # and this alias is configured in Solr to point to collection "http://server/solr/pdc-discovery-staging-1"
47
    # the returned writer URL will be "http://server/solr/pdc-discovery-staging-2".
48
    #
49
    # If the alias was configured to point to collection "http://server/solr/pdc-discovery-staging-2"
50
    # then the returned writer URL will be "http://server/solr/pdc-discovery-staging-1".
51
    def self.collection_writer_for_alias(solr_alias_uri, recreate)
1✔
52
      if config_set.nil?
1,784✔
53
        # We are not running in a Solr cloud environment - nothing to do.
54
        return solr_alias_uri.to_s
×
55
      end
56

57
      alternate_collection = alternate_collection_for_alias(solr_alias_uri)
1,784✔
58
      if collection_exist?(solr_alias_uri, alternate_collection)
1,784✔
59
        if recreate
1,784✔
60
          # Re-create it
61
          delete_collection!(solr_alias_uri, alternate_collection)
1✔
62
          create_collection(solr_alias_uri, alternate_collection)
1✔
63
        end
64
      else
65
        # Create it
66
        create_collection(solr_alias_uri, alternate_collection)
×
67
      end
68

69
      build_solr_url_for_collection(solr_alias_uri, alternate_collection)
1,784✔
70
    end
71

72
    # Returns the Solr URL based on the provided `solr_alias_uri`` but updated to use
73
    # the indicated `collection` instead of pointing to the alias.
74
    def self.build_solr_url_for_collection(solr_alias_uri, collection)
1✔
75
      build_uri(base_uri: solr_alias_uri, path: "/solr/#{collection}").to_s
1,785✔
76
    end
77

78
    def self.current_collection_for_alias(solr_alias_uri)
1✔
79
      alias_name = solr_alias_uri.path.split("/").last
1,789✔
80
      alias_list_query = build_uri(base_uri: solr_alias_uri, path: "/solr/admin/collections", query: "action=LISTALIASES")
1,789✔
81
      response = HTTParty.get(alias_list_query.to_s)
1,789✔
82
      # The response will indicate the actual collection the alias points to.
83
      collection_name = response.parsed_response.dig("aliases", alias_name) if response.code == 200
1,789✔
84
      collection_name || alias_name
1,789✔
85
    end
86

87
    def self.alternate_collection_for_alias(solr_alias_uri)
1✔
88
      solr_collection = current_collection_for_alias(solr_alias_uri)
1,787✔
89
      if solr_collection.end_with?("-1")
1,787✔
90
        solr_collection.gsub("-1", "-2")
4✔
91
      elsif solr_collection.end_with?("-2")
1,783✔
92
        solr_collection.gsub("-2", "-1")
1✔
93
      else
94
        solr_collection
1,782✔
95
      end
96
    end
97

98
    def self.collection_exist?(solr_alias_uri, collection_name)
1✔
99
      collection_list_query = build_uri(base_uri: solr_alias_uri, path: "/solr/admin/collections", query: "action=LIST")
1,786✔
100
      response = HTTParty.get(collection_list_query.to_s)
1,786✔
101
      collections = if response.code == 200
1,786✔
102
                      response.parsed_response.dig("collections") || []
1,786✔
103
                    else
104
                      []
×
105
                    end
106
      collections.any?(collection_name)
1,786✔
107
    end
108

109
    def self.create_collection(solr_alias_uri, collection_name)
1✔
110
      create_query = build_uri(
1✔
111
        base_uri: solr_alias_uri,
112
        path: "/solr/admin/collections",
113
        query: "action=CREATE&name=#{collection_name}&collection.configName=#{config_set}&numShards=1&replicationFactor=3"
114
      )
115
      response = HTTParty.get(create_query.to_s)
1✔
116
      if response.code == 200 && response.parsed_response.key?("success")
1✔
117
        collection_name
1✔
118
      else
NEW
119
        raise "Error creating collection #{collection_name}: #{response.parsed_response}"
×
120
      end
121
    end
122

123
    def self.delete_collection!(solr_alias_uri, collection_name)
1✔
124
      create_query = build_uri(
1✔
125
        base_uri: solr_alias_uri,
126
        path: "/solr/admin/collections",
127
        query: "action=DELETE&name=#{collection_name}"
128
      )
129
      response = HTTParty.get(create_query.to_s)
1✔
130
      response.code == 200
1✔
131
    end
132

133
    # Set the solr_alias to point to the current writer collection
134
    def self.update_solr_alias!
1✔
135
      writer_collection = collection_writer_url.split("/").last
2✔
136

137
      alias_name = alias_uri.path.split("/").last
2✔
138
      if alias_name == writer_collection
2✔
139
        # Nothing to do
140
        # (we are probably using standalone Solr in development)
141
        return true
1✔
142
      end
143

144
      create_query = build_uri(
1✔
145
        base_uri: alias_uri,
146
        path: "/solr/admin/collections",
147
        query: "action=CREATEALIAS&name=#{alias_name}&collections=#{writer_collection}"
148
      )
149
      response = HTTParty.get(create_query.to_s)
1✔
150
      response.code == 200
1✔
151
    end
152

153
    # Build a URI using another URI as the base.
154
    def self.build_uri(base_uri:, path:, query: nil)
1✔
155
      URI::HTTP.build(
5,363✔
156
        schema: base_uri.scheme,
157
        userinfo: base_uri.userinfo,
158
        host: base_uri.host,
159
        port: base_uri.port,
160
        path: path,
161
        query: query
162
      )
163
    end
164
  end
165
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc