px-service-client 1.2.2 → 1.2.3
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.
- checksums.yaml +4 -4
- data/README.md +24 -7
- data/lib/px/service/client/caching.rb +5 -7
- data/lib/px/service/client/version.rb +1 -1
- data/spec/px/service/client/base_spec.rb +52 -30
- data/spec/px/service/client/caching/caching_spec.rb +13 -8
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db46c3146668dad3c40c3a5cabc1feaf4743b745
|
4
|
+
data.tar.gz: 94824bed638685d41404aee9739453fdc2f79280
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 232d9cee11917707c1463cc1d53a9b1336225ef4cb22d5611a3dce074eb6b2feb9ca7e3b5420b69018f0d4acfa847407b37426519482ffd501df2c66875a1a59
|
7
|
+
data.tar.gz: 1d1b736be0ebc4a91957c09832a34ae892e16690d4f4df9dca211496bc6deb5c3d2f8f46e534999373b0ea51821453ce08cac9dd64a9c0e8bec64b8c2a85f340
|
data/README.md
CHANGED
@@ -38,7 +38,7 @@ This gem includes several common features used in 500px service client libraries
|
|
38
38
|
The features are:
|
39
39
|
|
40
40
|
#### Px::Service::Client::Base
|
41
|
-
This class provides a basic `make_request(method, url, ...)` method that produces an asynchronous request. The method immediately returns a `
|
41
|
+
This class provides a basic `make_request(method, url, ...)` method that produces an asynchronous request. The method immediately returns a `Future`. It works together with `Multiplexer`(discussed below) and uses [Typhoeus](https://github.com/typhoeus/typhoeus) as the underlying HTTP client to support asynchronicity.
|
42
42
|
|
43
43
|
**Customized clients usually inherit this class and include other features/mixins, if needed.**
|
44
44
|
|
@@ -55,7 +55,7 @@ multi = Px::Service::Client::Multiplexer.new
|
|
55
55
|
multi.context do
|
56
56
|
method = :get
|
57
57
|
url = 'http://www.example.com'
|
58
|
-
req = make_request(method, url) # returns a
|
58
|
+
req = make_request(method, url) # returns a Future
|
59
59
|
multi.do(req) # queues the request/future into hydra
|
60
60
|
end
|
61
61
|
|
@@ -64,9 +64,9 @@ multi.run # a blocking call, like hydra.run
|
|
64
64
|
```
|
65
65
|
`multi.context` encapsulates the block into a [`Fiber`](http://ruby-doc.org/core-2.2.0/Fiber.html) object and immediately runs (or `resume`, in Fiber's term) that fiber until the block explicitly gives up control. The method returns `multi` itself.
|
66
66
|
|
67
|
-
`multi.do(request_or_future,retries)` queues the request into `hydra`. It always returns a `
|
67
|
+
`multi.do(request_or_future,retries)` queues the request into `hydra`. It always returns a `Future`. A [`Typhoeus::Request`](https://github.com/typhoeus/typhoeus) will be converted into a `Future ` in this call.
|
68
68
|
|
69
|
-
Finally, `multi.run` starts `hydra` to execute the requests in parallel. The request is made as soon as the multiplexer is started. You get the results of the request by evaluating the value of the `
|
69
|
+
Finally, `multi.run` starts `hydra` to execute the requests in parallel. The request is made as soon as the multiplexer is started. You get the results of the request by evaluating the value of the `Future`.
|
70
70
|
|
71
71
|
#### Px::Service::Client::Caching
|
72
72
|
|
@@ -89,12 +89,29 @@ end
|
|
89
89
|
# An example of a cached request
|
90
90
|
result = cache_request(url, :last_resort, refresh_probability: 1) do
|
91
91
|
req = make_request(method, url)
|
92
|
+
response = @multi.do(req)
|
93
|
+
|
94
|
+
# cache_request() expects a future that returns the result to be cached
|
95
|
+
Px::Service::Client::Future.new do
|
96
|
+
JSON.parse(response.body)
|
97
|
+
end
|
92
98
|
end
|
93
99
|
```
|
94
100
|
|
95
|
-
`cache_request` expects a block that
|
101
|
+
`cache_request` expects a block that returns a `Future` object. The return value (usually the response body) of that future will be cached. `cache_request` always returns a future. By evaluating the future, i.e., via the `Future.value!` call, you get the result (whether cached or not).
|
102
|
+
|
103
|
+
|
104
|
+
**Note**: DO NOT cache the `Typhoeus::Response` directly (See the below code snippet), because the response object cannot be serializable to be stored in memcached. That's the reason why we see warning message: `You are trying to cache a Ruby object which cannot be serialized to memcached.`
|
105
|
+
|
106
|
+
```
|
107
|
+
# An incorrect example of using cache_request()
|
108
|
+
cache_request(url, :last_resort) do
|
109
|
+
req = make_request(method, url)
|
110
|
+
response = @multi.do(req) # DO NOT do this
|
111
|
+
end
|
96
112
|
|
97
|
-
|
113
|
+
```
|
114
|
+
Responses are cached in either a *last-resort* or *first-resort* manner.
|
98
115
|
|
99
116
|
*last-resort* means that the cached value is only used when the service client request fails (with a
|
100
117
|
`ServiceError`). If the service client request succeeds, there is a chance that the cache value may get refreshed. The `refresh_probability` is provided to let the cached value
|
@@ -125,7 +142,7 @@ end
|
|
125
142
|
req = make_request(method, url) # overrides Px::Service::Client::Base
|
126
143
|
```
|
127
144
|
|
128
|
-
Adds a circuit breaker to the client. `make_request` always returns `
|
145
|
+
Adds a circuit breaker to the client. `make_request` always returns `Future`
|
129
146
|
|
130
147
|
The circuit will open on any exception from the wrapped method, or if the request runs for longer than the `invocation_timeout`.
|
131
148
|
|
@@ -72,8 +72,7 @@ module Px::Service::Client
|
|
72
72
|
begin
|
73
73
|
raise ArgumentError.new('Block did not return a Future.') unless retry_response.is_a?(Future)
|
74
74
|
resp = retry_response.value!
|
75
|
-
|
76
|
-
entry = CacheEntry.new(config.cache_client, url, policy_group, resp.options)
|
75
|
+
entry = CacheEntry.new(config.cache_client, url, policy_group, resp)
|
77
76
|
|
78
77
|
# Only store a new result if we roll a 0
|
79
78
|
r = rand(refresh_probability)
|
@@ -88,7 +87,7 @@ module Px::Service::Client
|
|
88
87
|
end
|
89
88
|
|
90
89
|
entry.touch(expires_in, refresh_window: 1.minute)
|
91
|
-
|
90
|
+
entry.data
|
92
91
|
end
|
93
92
|
end
|
94
93
|
end
|
@@ -109,7 +108,7 @@ module Px::Service::Client
|
|
109
108
|
# don't also try to update the cache.
|
110
109
|
entry.touch(expires_in)
|
111
110
|
else
|
112
|
-
return Future.new {
|
111
|
+
return Future.new { entry.data }
|
113
112
|
end
|
114
113
|
end
|
115
114
|
|
@@ -119,8 +118,7 @@ module Px::Service::Client
|
|
119
118
|
begin
|
120
119
|
raise ArgumentError.new('Block did not return a Future.') unless retry_response.is_a?(Future)
|
121
120
|
resp = retry_response.value!
|
122
|
-
|
123
|
-
entry = CacheEntry.new(config.cache_client, url, policy_group, resp.options)
|
121
|
+
entry = CacheEntry.new(config.cache_client, url, policy_group, resp)
|
124
122
|
entry.store(expires_in)
|
125
123
|
resp
|
126
124
|
rescue Px::Service::ServiceError => ex
|
@@ -135,7 +133,7 @@ module Px::Service::Client
|
|
135
133
|
# Set the entry to be expired again (but reset the refresh window). This allows the next call to try again
|
136
134
|
# (assuming the circuit breaker is reset) but keeps the value in the cache in the meantime
|
137
135
|
entry.touch(0.seconds)
|
138
|
-
|
136
|
+
entry.data
|
139
137
|
end
|
140
138
|
end
|
141
139
|
|
@@ -67,8 +67,8 @@ describe Px::Service::Client::Base do
|
|
67
67
|
Typhoeus.stub(url).and_return(response)
|
68
68
|
end
|
69
69
|
|
70
|
-
shared_examples_for 'a request that returns a cached response' do
|
71
|
-
let(:cache_entry) { Px::Service::Client::Caching::CacheEntry.new(dalli, url, 'general',
|
70
|
+
shared_examples_for 'a request that returns a cached response body' do
|
71
|
+
let(:cache_entry) { Px::Service::Client::Caching::CacheEntry.new(dalli, url, 'general', response.body, Time.now + 1.year) }
|
72
72
|
|
73
73
|
before :each do
|
74
74
|
Typhoeus::Expectation.clear
|
@@ -80,8 +80,10 @@ describe Px::Service::Client::Base do
|
|
80
80
|
multi.context do
|
81
81
|
resp = multi.do(req)
|
82
82
|
end.run
|
83
|
-
|
84
|
-
|
83
|
+
|
84
|
+
Px::Service::Client::Future.new do
|
85
|
+
resp.options[:body]
|
86
|
+
end
|
85
87
|
end
|
86
88
|
end
|
87
89
|
|
@@ -94,12 +96,14 @@ describe Px::Service::Client::Base do
|
|
94
96
|
multi.context do
|
95
97
|
resp = multi.do(req)
|
96
98
|
end.run
|
97
|
-
|
98
|
-
|
99
|
+
|
100
|
+
Px::Service::Client::Future.new do
|
101
|
+
resp.options[:body]
|
102
|
+
end
|
99
103
|
end
|
100
104
|
end
|
101
105
|
|
102
|
-
it 'returns the cached response' do
|
106
|
+
it 'returns the cached response body' do
|
103
107
|
Typhoeus::Expectation.clear
|
104
108
|
Typhoeus.stub(url).and_return(response)
|
105
109
|
req = subject.send(:make_request, 'get', url)
|
@@ -108,10 +112,12 @@ describe Px::Service::Client::Base do
|
|
108
112
|
|
109
113
|
multi.context do
|
110
114
|
resp = multi.do(req)
|
111
|
-
expect(resp).to eq(cache_entry.data)
|
112
|
-
end
|
115
|
+
expect(resp.options[:body]).to eq(cache_entry.data)
|
116
|
+
end
|
113
117
|
|
114
|
-
|
118
|
+
Px::Service::Client::Future.new do
|
119
|
+
resp.options[:body]
|
120
|
+
end
|
115
121
|
end
|
116
122
|
end
|
117
123
|
end
|
@@ -120,7 +126,7 @@ describe Px::Service::Client::Base do
|
|
120
126
|
let(:strategy) { :first_resort }
|
121
127
|
let(:response) { successful_response }
|
122
128
|
|
123
|
-
it_behaves_like 'a request that returns a cached response'
|
129
|
+
it_behaves_like 'a request that returns a cached response body'
|
124
130
|
|
125
131
|
context 'when the request fails' do
|
126
132
|
let(:response) do
|
@@ -141,8 +147,10 @@ describe Px::Service::Client::Base do
|
|
141
147
|
resp = multi.do(req)
|
142
148
|
called = true
|
143
149
|
end.run
|
144
|
-
|
145
|
-
|
150
|
+
|
151
|
+
Px::Service::Client::Future.new do
|
152
|
+
resp.options[:body]
|
153
|
+
end
|
146
154
|
end
|
147
155
|
|
148
156
|
expect(called).to be_truthy
|
@@ -156,15 +164,17 @@ describe Px::Service::Client::Base do
|
|
156
164
|
multi.context do
|
157
165
|
resp = multi.do(req)
|
158
166
|
end.run
|
159
|
-
|
160
|
-
|
167
|
+
|
168
|
+
Px::Service::Client::Future.new do
|
169
|
+
resp.options[:body]
|
170
|
+
end
|
161
171
|
end.value!
|
162
172
|
}.to raise_error(Px::Service::ServiceError, 'Failed')
|
163
173
|
end
|
164
174
|
end
|
165
175
|
|
166
176
|
context 'when a response has been cached' do
|
167
|
-
it_behaves_like 'a request that returns a cached response'
|
177
|
+
it_behaves_like 'a request that returns a cached response body'
|
168
178
|
end
|
169
179
|
end
|
170
180
|
end
|
@@ -183,8 +193,10 @@ describe Px::Service::Client::Base do
|
|
183
193
|
resp = multi.do(req)
|
184
194
|
called = true
|
185
195
|
end.run
|
186
|
-
|
187
|
-
|
196
|
+
|
197
|
+
Px::Service::Client::Future.new do
|
198
|
+
resp.options[:body]
|
199
|
+
end
|
188
200
|
end
|
189
201
|
|
190
202
|
expect(called).to be_truthy
|
@@ -203,14 +215,16 @@ describe Px::Service::Client::Base do
|
|
203
215
|
called = false
|
204
216
|
req = subject.send(:make_request, 'get', url)
|
205
217
|
|
206
|
-
subject.cache_request(req.request.url, strategy: strategy) do
|
218
|
+
subject.cache_request(req.request.url, strategy: strategy, refresh_probability: 0) do
|
207
219
|
resp = nil
|
208
220
|
multi.context do
|
209
221
|
resp = multi.do(req)
|
210
222
|
called = true
|
211
223
|
end.run
|
212
|
-
|
213
|
-
|
224
|
+
|
225
|
+
Px::Service::Client::Future.new do
|
226
|
+
resp.options[:body]
|
227
|
+
end
|
214
228
|
end
|
215
229
|
|
216
230
|
expect(called).to be_truthy
|
@@ -225,14 +239,16 @@ describe Px::Service::Client::Base do
|
|
225
239
|
multi.context do
|
226
240
|
resp = multi.do(req)
|
227
241
|
end.run
|
228
|
-
|
229
|
-
|
242
|
+
|
243
|
+
Px::Service::Client::Future.new do
|
244
|
+
resp.options[:body]
|
245
|
+
end
|
230
246
|
end.value!
|
231
247
|
}.to raise_error(Px::Service::ServiceError, 'Failed')
|
232
248
|
end
|
233
249
|
end
|
234
250
|
|
235
|
-
context 'when a response has been cached' do
|
251
|
+
context 'when a response body has been cached' do
|
236
252
|
before :each do
|
237
253
|
Typhoeus::Expectation.clear
|
238
254
|
Typhoeus.stub(url).and_return(successful_response)
|
@@ -245,7 +261,9 @@ describe Px::Service::Client::Base do
|
|
245
261
|
resp = multi.do(req)
|
246
262
|
end.run
|
247
263
|
|
248
|
-
|
264
|
+
Px::Service::Client::Future.new do
|
265
|
+
resp.options[:body]
|
266
|
+
end
|
249
267
|
end
|
250
268
|
end
|
251
269
|
|
@@ -259,13 +277,15 @@ describe Px::Service::Client::Base do
|
|
259
277
|
called = true
|
260
278
|
end.run
|
261
279
|
|
262
|
-
|
280
|
+
Px::Service::Client::Future.new do
|
281
|
+
resp.options[:body]
|
282
|
+
end
|
263
283
|
end
|
264
284
|
|
265
285
|
expect(called).to be_truthy
|
266
286
|
end
|
267
287
|
|
268
|
-
it 'returns the cached response' do
|
288
|
+
it 'returns the cached response body' do
|
269
289
|
Typhoeus::Expectation.clear
|
270
290
|
Typhoeus.stub(url).and_return(response)
|
271
291
|
req = subject.send(:make_request, 'get', url)
|
@@ -275,9 +295,11 @@ describe Px::Service::Client::Base do
|
|
275
295
|
multi.context do
|
276
296
|
resp = multi.do(req)
|
277
297
|
end.run
|
278
|
-
|
279
|
-
|
280
|
-
|
298
|
+
|
299
|
+
Px::Service::Client::Future.new do
|
300
|
+
resp.options[:body]
|
301
|
+
end
|
302
|
+
end.value!['status']).to be(200)
|
281
303
|
end
|
282
304
|
end
|
283
305
|
|
@@ -39,7 +39,7 @@ describe Px::Service::Client::Caching do
|
|
39
39
|
it "should call the block" do
|
40
40
|
called = false
|
41
41
|
subject.cache_request(url, strategy: strategy) do
|
42
|
-
called = true
|
42
|
+
Px::Service::Client::Future.new { called = true }
|
43
43
|
end
|
44
44
|
|
45
45
|
expect(called).to be_truthy
|
@@ -131,7 +131,7 @@ describe Px::Service::Client::Caching do
|
|
131
131
|
it "returns the cached response on failure" do
|
132
132
|
expect(subject.cache_request(url, strategy: strategy) do
|
133
133
|
Px::Service::Client::Future.new { raise Px::Service::ServiceError.new("Error", 500) }
|
134
|
-
end.value
|
134
|
+
end.value!).to eq(response.options)
|
135
135
|
end
|
136
136
|
|
137
137
|
it "does not returns the cached response on request error" do
|
@@ -195,8 +195,10 @@ describe Px::Service::Client::Caching do
|
|
195
195
|
|
196
196
|
it "returns the response" do
|
197
197
|
expect(subject.cache_request(url, strategy: strategy) do
|
198
|
-
|
199
|
-
|
198
|
+
Future.new do
|
199
|
+
nil
|
200
|
+
end
|
201
|
+
end.value!).to eq(response.options)
|
200
202
|
end
|
201
203
|
end
|
202
204
|
end
|
@@ -217,7 +219,10 @@ describe Px::Service::Client::Caching do
|
|
217
219
|
it "invokes the block" do
|
218
220
|
called = false
|
219
221
|
subject.cache_request(url, strategy: strategy) do |u|
|
220
|
-
|
222
|
+
Px::Service::Client::Future.new do
|
223
|
+
called = true
|
224
|
+
{ stub: "stub str" }.to_hash
|
225
|
+
end
|
221
226
|
end
|
222
227
|
|
223
228
|
expect(called).to be_truthy
|
@@ -252,7 +257,7 @@ describe Px::Service::Client::Caching do
|
|
252
257
|
end.run
|
253
258
|
|
254
259
|
resp
|
255
|
-
end.value
|
260
|
+
end.value!).to eq(response.options)
|
256
261
|
|
257
262
|
expect(called).to be_falsey
|
258
263
|
|
@@ -272,13 +277,13 @@ describe Px::Service::Client::Caching do
|
|
272
277
|
|
273
278
|
expect(subject.cache_request(url, strategy: strategy) do
|
274
279
|
nil
|
275
|
-
end.value
|
280
|
+
end.value).to eq(response.options)
|
276
281
|
end
|
277
282
|
|
278
283
|
it "returns the cached response on failure" do
|
279
284
|
expect(subject.cache_request(url, strategy: strategy) do
|
280
285
|
Px::Service::Client::Future.new { raise Px::Service::ServiceError.new("Error", 500) }
|
281
|
-
end.value
|
286
|
+
end.value!).to eq(response.options)
|
282
287
|
end
|
283
288
|
|
284
289
|
it "does not returns the cached response on request error" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: px-service-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Micacchi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-07-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: will_paginate
|