rsolr 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES.txt +3 -1
- data/README.rdoc +18 -18
- data/lib/rsolr/client.rb +39 -1
- data/lib/rsolr/connection.rb +2 -0
- data/lib/rsolr/response.rb +10 -4
- data/lib/rsolr.rb +2 -2
- data/spec/api/client_spec.rb +32 -0
- data/spec/api/connection_spec.rb +21 -0
- metadata +10 -10
data/CHANGES.txt
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
1.0.8
|
2
2
|
- Fix connection refused errors in specs + add basic auth support (Denis Goeury)
|
3
|
+
- Ability to set :retry_503, the number of retry attempts for a 503 response
|
4
|
+
with a Retry-After header.
|
3
5
|
1.0.7
|
4
6
|
- Response body encoding is set to response charset in Ruby >= 1.9
|
5
7
|
- Ability to set :read_timeout and :open_timeout when creating new instance of RSolr
|
@@ -14,4 +16,4 @@
|
|
14
16
|
- Jeweler is no longer used for building the gemspec
|
15
17
|
1.0.3
|
16
18
|
- Proper encodings in Ruby 1.9
|
17
|
-
- Applied pull request from https://github.com/mwmitchell/rsolr/pull/20
|
19
|
+
- Applied pull request from https://github.com/mwmitchell/rsolr/pull/20
|
data/README.rdoc
CHANGED
@@ -36,6 +36,13 @@ The :response attribute contains the original response. This object contains the
|
|
36
36
|
The read and connect timeout settings can be set when creating a new instance of RSolr:
|
37
37
|
solr = RSolr.connect(:read_timeout => 120, :open_timeout => 120)
|
38
38
|
|
39
|
+
== Retry 503s
|
40
|
+
A 503 is usually a temporary error which RSolr may retry if requested. You may specify the number of retry attempts with the :retry_503 option.
|
41
|
+
|
42
|
+
Only requests which specify a Retry-After header will be retried, after waiting the indicated retry interval, otherwise RSolr will treat the request as a 500. You may specify a maximum Retry-After interval to wait with the :retry_after_limit option (default: one second).
|
43
|
+
solr = RSolr.connect(:retry_503 => 1, :retry_after_limit => 1)
|
44
|
+
|
45
|
+
|
39
46
|
== Querying
|
40
47
|
Use the #get / #post method to send search requests to the /select handler:
|
41
48
|
response = solr.get 'select', :params => {
|
@@ -176,27 +183,20 @@ The default response format is Ruby. When the :wt param is set to :ruby, the res
|
|
176
183
|
* Send me a pull request. Bonus points for topic branches.
|
177
184
|
|
178
185
|
==Contributors
|
179
|
-
*
|
180
|
-
* Dmitry Lihachev
|
181
|
-
* Lucas Souza
|
182
|
-
* Peter Kieltyka
|
183
|
-
* Rob Di Marco
|
186
|
+
* Nathan Witmer
|
184
187
|
* Magnus Bergmark
|
185
|
-
*
|
186
|
-
* Chris Beer
|
187
|
-
* Craig Smith
|
188
|
+
* shima
|
188
189
|
* Randy Souza
|
189
|
-
* Colin Steele
|
190
|
-
* Peter Kieltyka
|
191
|
-
* Lorenzo Riccucci
|
192
|
-
* Mike Perham
|
193
190
|
* Mat Brown
|
194
|
-
* Shairon Toledo
|
195
|
-
* Matthew Rudy
|
196
|
-
* Fouad Mardini
|
197
191
|
* Jeremy Hinegardner
|
198
|
-
*
|
199
|
-
*
|
192
|
+
* Denis Goeury
|
193
|
+
* shairon toledo
|
194
|
+
* Rob Di Marco
|
195
|
+
* Peter Kieltyka
|
196
|
+
* Mike Perham
|
197
|
+
* Lucas Souza
|
198
|
+
* Dmitry Lihachev
|
199
|
+
* Antoine Latter
|
200
200
|
|
201
201
|
==Author
|
202
202
|
|
@@ -204,4 +204,4 @@ Matt Mitchell <mailto:goodieboy@gmail.com>
|
|
204
204
|
|
205
205
|
==Copyright
|
206
206
|
|
207
|
-
Copyright (c) 2008-2010 Matt Mitchell. See LICENSE for details.
|
207
|
+
Copyright (c) 2008-2010 Matt Mitchell. See LICENSE for details.
|
data/lib/rsolr/client.rb
CHANGED
@@ -155,7 +155,7 @@ class RSolr::Client
|
|
155
155
|
# then passes the request/response into +adapt_response+.
|
156
156
|
def send_and_receive path, opts
|
157
157
|
request_context = build_request path, opts
|
158
|
-
[:open_timeout, :read_timeout].each do |k|
|
158
|
+
[:open_timeout, :read_timeout, :retry_503, :retry_after_limit].each do |k|
|
159
159
|
request_context[k] = @options[k]
|
160
160
|
end
|
161
161
|
execute request_context
|
@@ -163,9 +163,47 @@ class RSolr::Client
|
|
163
163
|
|
164
164
|
#
|
165
165
|
def execute request_context
|
166
|
+
|
166
167
|
raw_response = connection.execute self, request_context
|
168
|
+
|
169
|
+
while retry_503?(request_context, raw_response)
|
170
|
+
request_context[:retry_503] -= 1
|
171
|
+
sleep retry_after(raw_response)
|
172
|
+
raw_response = connection.execute self, request_context
|
173
|
+
end
|
174
|
+
|
167
175
|
adapt_response(request_context, raw_response) unless raw_response.nil?
|
168
176
|
end
|
177
|
+
|
178
|
+
def retry_503?(request_context, response)
|
179
|
+
return false if response.nil?
|
180
|
+
status = response[:status] && response[:status].to_i
|
181
|
+
return false unless status == 503
|
182
|
+
retry_503 = request_context[:retry_503]
|
183
|
+
return false unless retry_503 && retry_503 > 0
|
184
|
+
retry_after_limit = request_context[:retry_after_limit] || 1
|
185
|
+
retry_after = retry_after(response)
|
186
|
+
return false unless retry_after && retry_after <= retry_after_limit
|
187
|
+
true
|
188
|
+
end
|
189
|
+
|
190
|
+
# Retry-After can be a relative number of seconds from now, or an RFC 1123 Date.
|
191
|
+
# If the latter, attempt to convert it to a relative time in seconds.
|
192
|
+
def retry_after(response)
|
193
|
+
retry_after = Array(response[:headers]['Retry-After'] || response[:headers]['retry-after']).flatten.first.to_s
|
194
|
+
if retry_after =~ /\A[0-9]+\Z/
|
195
|
+
retry_after = retry_after.to_i
|
196
|
+
else
|
197
|
+
begin
|
198
|
+
retry_after_date = DateTime.parse(retry_after)
|
199
|
+
retry_after = retry_after_date.to_time - Time.now
|
200
|
+
retry_after = nil if retry_after < 0
|
201
|
+
rescue ArgumentError => e
|
202
|
+
retry_after = retry_after.to_i
|
203
|
+
end
|
204
|
+
end
|
205
|
+
retry_after
|
206
|
+
end
|
169
207
|
|
170
208
|
# +build_request+ accepts a path and options hash,
|
171
209
|
# then prepares a normalized hash to return for sending
|
data/lib/rsolr/connection.rb
CHANGED
@@ -15,6 +15,8 @@ class RSolr::Connection
|
|
15
15
|
response = h.request request
|
16
16
|
charset = response.type_params["charset"]
|
17
17
|
{:status => response.code.to_i, :headers => response.to_hash, :body => force_charset(response.body, charset)}
|
18
|
+
rescue Errno::ECONNREFUSED => e
|
19
|
+
raise(Errno::ECONNREFUSED.new(request_context.inspect))
|
18
20
|
# catch the undefined closed? exception -- this is a confirmed ruby bug
|
19
21
|
rescue NoMethodError
|
20
22
|
$!.message == "undefined method `closed?' for nil:NilClass" ?
|
data/lib/rsolr/response.rb
CHANGED
@@ -5,8 +5,8 @@ module RSolr::Response
|
|
5
5
|
base["response"]["docs"].tap do |d|
|
6
6
|
d.extend PaginatedDocSet
|
7
7
|
d.per_page = base.request[:params]["rows"]
|
8
|
-
d.
|
9
|
-
d.
|
8
|
+
d.page_start = base.request[:params]["start"]
|
9
|
+
d.page_total = base["response"]["numFound"].to_s.to_i
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
@@ -14,7 +14,13 @@ module RSolr::Response
|
|
14
14
|
# A response module which gets mixed into the solr ["response"]["docs"] array.
|
15
15
|
module PaginatedDocSet
|
16
16
|
|
17
|
-
attr_accessor :
|
17
|
+
attr_accessor :page_start, :per_page, :page_total
|
18
|
+
if not (Object.const_defined?("RUBY_ENGINE") and Object::RUBY_ENGINE=='rbx')
|
19
|
+
alias_method(:start,:page_start)
|
20
|
+
alias_method(:start=,:page_start=)
|
21
|
+
alias_method(:total,:page_total)
|
22
|
+
alias_method(:total=,:page_total=)
|
23
|
+
end
|
18
24
|
|
19
25
|
# Returns the current page calculated from 'rows' and 'start'
|
20
26
|
def current_page
|
@@ -48,4 +54,4 @@ module RSolr::Response
|
|
48
54
|
|
49
55
|
end
|
50
56
|
|
51
|
-
end
|
57
|
+
end
|
data/lib/rsolr.rb
CHANGED
@@ -6,7 +6,7 @@ module RSolr
|
|
6
6
|
|
7
7
|
%W(Response Char Client Error Connection Uri Xml).each{|n|autoload n.to_sym, "rsolr/#{n.downcase}"}
|
8
8
|
|
9
|
-
def self.version; "1.0.
|
9
|
+
def self.version; "1.0.9" end
|
10
10
|
|
11
11
|
VERSION = self.version
|
12
12
|
|
@@ -19,4 +19,4 @@ module RSolr
|
|
19
19
|
# RSolr.escape
|
20
20
|
extend Char
|
21
21
|
|
22
|
-
end
|
22
|
+
end
|
data/spec/api/client_spec.rb
CHANGED
@@ -34,6 +34,38 @@ describe "RSolr::Client" do
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
+
context "execute" do
|
38
|
+
include ClientHelper
|
39
|
+
let :request_context do
|
40
|
+
{
|
41
|
+
:method => :post,
|
42
|
+
:params => {},
|
43
|
+
:data => nil,
|
44
|
+
:headers => {},
|
45
|
+
:path => '',
|
46
|
+
:uri => client.base_uri,
|
47
|
+
:retry_503 => 1
|
48
|
+
}
|
49
|
+
end
|
50
|
+
it "should retry 503s if requested" do
|
51
|
+
client.connection.should_receive(:execute).exactly(2).times.and_return(
|
52
|
+
{:status => 503, :body => "{}", :headers => {'Retry-After' => 0}},
|
53
|
+
{:status => 200, :body => "{}", :headers => {}}
|
54
|
+
)
|
55
|
+
client.execute request_context
|
56
|
+
end
|
57
|
+
it "should not retry a 503 if the retry-after is too large" do
|
58
|
+
client.connection.should_receive(:execute).exactly(1).times.and_return(
|
59
|
+
{:status => 503, :body => "{}", :headers => {'Retry-After' => 10}}
|
60
|
+
)
|
61
|
+
lambda {
|
62
|
+
Timeout.timeout(0.5) do
|
63
|
+
client.execute({:retry_after_limit => 0}.merge(request_context))
|
64
|
+
end
|
65
|
+
}.should raise_error(RSolr::Error::Http)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
37
69
|
context "post" do
|
38
70
|
include ClientHelper
|
39
71
|
it "should pass the expected params to the connection's #execute method" do
|
data/spec/api/connection_spec.rb
CHANGED
@@ -57,6 +57,27 @@ describe "RSolr::Connection" do
|
|
57
57
|
subject.execute client, {:uri => URI.parse("http://localhost/some_uri"), :method => :get}
|
58
58
|
end
|
59
59
|
end
|
60
|
+
|
61
|
+
context "connection refused" do
|
62
|
+
let(:client) { mock.as_null_object }
|
63
|
+
|
64
|
+
let(:http) { mock(Net::HTTP).as_null_object }
|
65
|
+
let(:request_context) {
|
66
|
+
{:uri => URI.parse("http://localhost/some_uri"), :method => :get, :open_timeout => 42}
|
67
|
+
}
|
68
|
+
subject { RSolr::Connection.new }
|
69
|
+
|
70
|
+
before do
|
71
|
+
Net::HTTP.stub(:new) { http }
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should configure Net:HTTP open_timeout" do
|
75
|
+
http.should_receive(:request).and_raise(Errno::ECONNREFUSED)
|
76
|
+
lambda {
|
77
|
+
subject.execute client, request_context
|
78
|
+
}.should raise_error(Errno::ECONNREFUSED, /#{request_context}/)
|
79
|
+
end
|
80
|
+
end
|
60
81
|
|
61
82
|
describe "basic auth support" do
|
62
83
|
let(:http) { mock(Net::HTTP).as_null_object }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rsolr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.9
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -29,11 +29,11 @@ authors:
|
|
29
29
|
autorequire:
|
30
30
|
bindir: bin
|
31
31
|
cert_chain: []
|
32
|
-
date:
|
32
|
+
date: 2013-03-29 00:00:00.000000000Z
|
33
33
|
dependencies:
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
35
|
name: builder
|
36
|
-
requirement: &
|
36
|
+
requirement: &70317957140320 !ruby/object:Gem::Requirement
|
37
37
|
none: false
|
38
38
|
requirements:
|
39
39
|
- - ! '>='
|
@@ -41,10 +41,10 @@ dependencies:
|
|
41
41
|
version: 2.1.2
|
42
42
|
type: :runtime
|
43
43
|
prerelease: false
|
44
|
-
version_requirements: *
|
44
|
+
version_requirements: *70317957140320
|
45
45
|
- !ruby/object:Gem::Dependency
|
46
46
|
name: rake
|
47
|
-
requirement: &
|
47
|
+
requirement: &70317957139580 !ruby/object:Gem::Requirement
|
48
48
|
none: false
|
49
49
|
requirements:
|
50
50
|
- - ~>
|
@@ -52,10 +52,10 @@ dependencies:
|
|
52
52
|
version: 0.9.2
|
53
53
|
type: :development
|
54
54
|
prerelease: false
|
55
|
-
version_requirements: *
|
55
|
+
version_requirements: *70317957139580
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: rdoc
|
58
|
-
requirement: &
|
58
|
+
requirement: &70317957138980 !ruby/object:Gem::Requirement
|
59
59
|
none: false
|
60
60
|
requirements:
|
61
61
|
- - ~>
|
@@ -63,10 +63,10 @@ dependencies:
|
|
63
63
|
version: 3.9.4
|
64
64
|
type: :development
|
65
65
|
prerelease: false
|
66
|
-
version_requirements: *
|
66
|
+
version_requirements: *70317957138980
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
68
|
name: rspec
|
69
|
-
requirement: &
|
69
|
+
requirement: &70317957138400 !ruby/object:Gem::Requirement
|
70
70
|
none: false
|
71
71
|
requirements:
|
72
72
|
- - ~>
|
@@ -74,7 +74,7 @@ dependencies:
|
|
74
74
|
version: 2.6.0
|
75
75
|
type: :development
|
76
76
|
prerelease: false
|
77
|
-
version_requirements: *
|
77
|
+
version_requirements: *70317957138400
|
78
78
|
description: RSolr aims to provide a simple and extensible library for working with
|
79
79
|
Solr
|
80
80
|
email:
|