routemaster-client 2.0.0 → 2.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1ee29c57b725f321cc404fba4ac361d7ba277d1a
4
- data.tar.gz: 707c11f90c92de25d0b7a40ed6b452e61b2016af
3
+ metadata.gz: 4ab7db72b3f45ca016af6ddfcd31727c08448d04
4
+ data.tar.gz: 864cc421186071bf194c01c230f778016ab4011c
5
5
  SHA512:
6
- metadata.gz: b63264e4bf56e517980d49716a4f7b4f5e7abfd0f8a0c6ccb0c95d22284e7ce13263182483ac9cac081e4f4fcc70c4fa7325c19d1660ac4aec47fea59c3ec195
7
- data.tar.gz: 8d67555f4b949ba7245340ac46a4ad85d9fb307a6f829755e783f20e83018db0d218aedd34db719998522009e787ca1b910fcb77ff01f7a1ad1a2703fed80df4
6
+ metadata.gz: d48921d988693488e7aed1b03b22526a88cd320eb85ce97976c32b0b0458fd79703043a0ef9f3e82971a9afcc3712f6427ce55c7aacc3ce5b00af81dd15ca24e
7
+ data.tar.gz: 856f4e0a2f340dbbe9d5c8b13e39fea9026b94ce48f53ec81bbca6da1ba5d860fd4460339cbd5fefdf3f43129cc51bc63130b81aa5e4132a2a84ee350bd34573
data/Gemfile CHANGED
@@ -15,4 +15,5 @@ gem 'pry-byebug'
15
15
  gem 'rack-test'
16
16
  gem 'simplecov'
17
17
  gem 'codeclimate-test-reporter', require: nil
18
+ gem 'sidekiq'
18
19
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- routemaster-client (2.0.0)
4
+ routemaster-client (2.1.0)
5
5
  faraday (>= 0.9.0)
6
6
  oj (~> 2.17)
7
7
  typhoeus (~> 1.1)
@@ -16,6 +16,8 @@ GEM
16
16
  codeclimate-test-reporter (1.0.3)
17
17
  simplecov
18
18
  coderay (1.1.1)
19
+ concurrent-ruby (1.0.2)
20
+ connection_pool (2.2.1)
19
21
  crack (0.4.3)
20
22
  safe_yaml (~> 1.0.0)
21
23
  diff-lcs (1.2.5)
@@ -64,12 +66,15 @@ GEM
64
66
  psych (2.2.1)
65
67
  public_suffix (2.0.4)
66
68
  rack (2.0.1)
69
+ rack-protection (1.5.3)
70
+ rack
67
71
  rack-test (0.6.3)
68
72
  rack (>= 1.0)
69
73
  rake (11.3.0)
70
74
  rb-fsevent (0.9.8)
71
75
  rb-inotify (0.9.7)
72
76
  ffi (>= 0.5.0)
77
+ redis (3.3.2)
73
78
  rspec (3.5.0)
74
79
  rspec-core (~> 3.5.0)
75
80
  rspec-expectations (~> 3.5.0)
@@ -86,6 +91,11 @@ GEM
86
91
  ruby_dep (1.5.0)
87
92
  safe_yaml (1.0.4)
88
93
  shellany (0.0.1)
94
+ sidekiq (4.2.1)
95
+ concurrent-ruby (~> 1.0)
96
+ connection_pool (~> 2.2, >= 2.2.0)
97
+ rack-protection (~> 1.5)
98
+ redis (~> 3.2, >= 3.2.1)
89
99
  simplecov (0.12.0)
90
100
  docile (~> 1.1.0)
91
101
  json (>= 1.8, < 3)
@@ -113,6 +123,7 @@ DEPENDENCIES
113
123
  rack-test
114
124
  rake
115
125
  routemaster-client!
126
+ sidekiq
116
127
  simplecov
117
128
  webmock
118
129
 
data/README.md CHANGED
@@ -34,6 +34,11 @@ You can also specify a timeout value in seconds if you like with the ```timeout`
34
34
  Routemaster::Client.new(url: 'https://bus.example.com', uuid: 'demo', timeout: 2)
35
35
  ```
36
36
 
37
+ If you are using Sidekiq in your project, you can specify the usage of a Sidekiq backend, where event sending will be processed asynchronously.
38
+
39
+ ```ruby
40
+ Routemaster::Client.new(url, 'https://bus.example.com', uuid: 'demo', backend_type: Routemaster::Client::Backends::Sidekiq)
41
+ ```
37
42
 
38
43
  **Push** an event about an entity in the topic `widgets` with a callback URL:
39
44
 
@@ -0,0 +1,24 @@
1
+ require 'routemaster/client/connection'
2
+
3
+ module Routemaster
4
+ class Client
5
+ module Backends
6
+ class Sidekiq
7
+ class Worker
8
+ include ::Sidekiq::Worker
9
+
10
+ def perform(event, topic, callback, timestamp, options)
11
+ conn = Routemaster::Client::Connection.new(_symbolize_keys(options))
12
+ conn.send_event(event, topic, callback, timestamp)
13
+ end
14
+
15
+ private
16
+
17
+ def _symbolize_keys(hash)
18
+ Hash[hash.map{|(k,v)| [k.to_sym,v]}]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ require 'sidekiq'
2
+ require 'routemaster/client/backends/sidekiq/worker'
3
+
4
+ module Routemaster
5
+ class Client
6
+ module Backends
7
+ class Sidekiq
8
+ @queue = :realtime
9
+
10
+ class << self
11
+ def configure(options)
12
+ new(options)
13
+ end
14
+ end
15
+
16
+ def initialize(options)
17
+ @_options = options
18
+ end
19
+
20
+ def send_event(event, topic, callback, timestamp = nil)
21
+ Worker.perform_async(event, topic, callback, timestamp, @_options)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ require 'routemaster/client/connection'
2
+
3
+ module Routemaster
4
+ class Client
5
+ module Backends
6
+ class Synchronous
7
+
8
+ class << self
9
+ def configure(options)
10
+ new(options)
11
+ end
12
+ end
13
+
14
+ def initialize(options)
15
+ @conn = Routemaster::Client::Connection.new(options)
16
+ end
17
+
18
+ def send_event(event, topic, callback, timestamp = nil)
19
+ @conn.send_event(event, topic, callback, timestamp)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,10 @@
1
+ module Routemaster
2
+ class Client
3
+ module Backends
4
+ NAMES = ["Routemaster::Client::Backends::Synchronous", "Routemaster::Client::Backends::Sidekiq"]
5
+
6
+ autoload 'Synchronous', 'routemaster/client/backends/synchronous'
7
+ autoload 'Sidekiq', 'routemaster/client/backends/sidekiq'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,75 @@
1
+ require 'forwardable'
2
+
3
+ # Internal class used by Routemaster::Client
4
+
5
+ module Routemaster
6
+ class Client
7
+ class Connection
8
+
9
+ def initialize(options)
10
+ @_url = options[:url]
11
+ @_uuid = options[:uuid]
12
+ @_timeout = options.fetch(:timeout, 1)
13
+ @_verify_ssl = options.fetch(:verify_ssl, true)
14
+ end
15
+
16
+ def http(method, path, &block)
17
+ _conn.send(method, path, &block)
18
+ end
19
+
20
+ def post(path, &block)
21
+ http(:post, path, &block)
22
+ end
23
+
24
+ def get(path, &block)
25
+ http(:get, path, &block)
26
+ end
27
+
28
+ def delete(path, &block)
29
+ http(:delete, path, &block)
30
+ end
31
+
32
+ def send_event(event, topic, callback, timestamp = nil)
33
+ data = { type: event, url: callback, timestamp: timestamp }
34
+
35
+ response = post("/topics/#{topic}") do |r|
36
+ r.headers['Content-Type'] = 'application/json'
37
+ r.body = Oj.dump(_stringify_keys data)
38
+ end
39
+ fail "event rejected (#{response.status})" unless response.success?
40
+ end
41
+
42
+ def subscribe(options)
43
+ response = post('/subscription') do |r|
44
+ r.headers['Content-Type'] = 'application/json'
45
+ r.body = Oj.dump(_stringify_keys options)
46
+ end
47
+
48
+ unless response.success?
49
+ raise 'subscribe rejected'
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def _stringify_keys(hash)
56
+ hash.dup.tap do |h|
57
+ h.keys.each do |k|
58
+ h[k.to_s] = h.delete(k)
59
+ end
60
+ end
61
+ end
62
+
63
+ def _conn
64
+ @_conn ||= Faraday.new(@_url, ssl: { verify: @_verify_ssl }) do |f|
65
+ f.request :retry, max: 2, interval: 100e-3, backoff_factor: 2
66
+ f.request :basic_auth, @_uuid, 'x'
67
+ f.adapter :typhoeus
68
+
69
+ f.options.timeout = @_timeout
70
+ f.options.open_timeout = @_timeout
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -1,5 +1,5 @@
1
1
  module Routemaster
2
2
  class Client
3
- VERSION = '2.0.0'
3
+ VERSION = '2.1.0'
4
4
  end
5
5
  end
@@ -1,3 +1,5 @@
1
+ require 'routemaster/client/backends'
2
+ require 'routemaster/client/connection'
1
3
  require 'routemaster/client/version'
2
4
  require 'routemaster/topic'
3
5
  require 'uri'
@@ -9,17 +11,22 @@ require 'oj'
9
11
 
10
12
  module Routemaster
11
13
  class Client
12
-
14
+
13
15
  def initialize(options = {})
14
- @_url = _assert_valid_url(options[:url])
15
- @_uuid = options[:uuid]
16
- @_timeout = options.fetch(:timeout, 1)
17
- @_verify_ssl = options.fetch(:verify_ssl, true)
16
+ @_options = options.tap do |o|
17
+ o[:timeout] ||= 1
18
+ o[:backend_type] ||= Backends::Synchronous
19
+ end
20
+
21
+ @_backend_type = @_options.fetch(:backend_type)
22
+
23
+ _assert_valid_url(@_options[:url])
24
+ _assert_valid_backend_type(@_backend_type)
25
+ _assert (@_options[:uuid] =~ /^[a-z0-9_-]{1,64}$/), 'uuid should be alpha'
26
+ _assert_valid_timeout(@_options[:timeout])
18
27
 
19
- _assert (options[:uuid] =~ /^[a-z0-9_-]{1,64}$/), 'uuid should be alpha'
20
- _assert_valid_timeout(@_timeout)
21
28
 
22
- unless options[:lazy]
29
+ unless @_options[:lazy]
23
30
  _conn.get('/pulse').tap do |response|
24
31
  raise 'cannot connect to bus' unless response.success?
25
32
  end
@@ -53,22 +60,14 @@ module Routemaster
53
60
 
54
61
  options[:topics].each { |t| _assert_valid_topic(t) }
55
62
  _assert_valid_url(options[:callback])
56
-
57
- response = _post('/subscription') do |r|
58
- r.headers['Content-Type'] = 'application/json'
59
- r.body = Oj.dump(_stringify_keys options)
60
- end
61
-
62
- unless response.success?
63
- raise 'subscribe rejected'
64
- end
63
+ _conn.subscribe(options)
65
64
  end
66
65
 
67
66
  def unsubscribe(*topics)
68
67
  topics.each { |t| _assert_valid_topic(t) }
69
68
 
70
69
  topics.each do |t|
71
- response = _delete("/subscriber/topics/#{t}")
70
+ response = _conn.delete("/subscriber/topics/#{t}")
72
71
 
73
72
  unless response.success?
74
73
  raise 'unsubscribe rejected'
@@ -77,7 +76,7 @@ module Routemaster
77
76
  end
78
77
 
79
78
  def unsubscribe_all
80
- response = _delete('/subscriber')
79
+ response = _conn.delete('/subscriber')
81
80
 
82
81
  unless response.success?
83
82
  raise 'unsubscribe all rejected'
@@ -87,7 +86,7 @@ module Routemaster
87
86
  def delete_topic(topic)
88
87
  _assert_valid_topic(topic)
89
88
 
90
- response = _delete("/topics/#{topic}")
89
+ response = _conn.delete("/topics/#{topic}")
91
90
 
92
91
  unless response.success?
93
92
  raise 'failed to delete topic'
@@ -95,7 +94,7 @@ module Routemaster
95
94
  end
96
95
 
97
96
  def monitor_topics
98
- response = _get('/topics') do |r|
97
+ response = _conn.get('/topics') do |r|
99
98
  r.headers['Content-Type'] = 'application/json'
100
99
  end
101
100
 
@@ -108,17 +107,8 @@ module Routemaster
108
107
  end
109
108
  end
110
109
 
111
-
112
110
  private
113
111
 
114
- def _stringify_keys(hash)
115
- hash.dup.tap do |h|
116
- h.keys.each do |k|
117
- h[k.to_s] = h.delete(k)
118
- end
119
- end
120
- end
121
-
122
112
  def _assert_valid_timeout(timeout)
123
113
  _assert (0..3_600_000).include?(timeout), 'bad timeout'
124
114
  end
@@ -141,49 +131,29 @@ module Routemaster
141
131
  _assert timestamp.kind_of?(Integer), 'not an integer'
142
132
  end
143
133
 
134
+ def _assert_valid_backend_type(backend_type)
135
+ backends = Backends::NAMES
136
+ _assert backends.include?(backend_type.to_s), "unknown backend type, must be one of #{backends.map{ |w| "Routemaster::Backends::#{w}" }.join(", ")}"
137
+ backend_type
138
+ end
139
+
144
140
  def _send_event(event, topic, callback, timestamp = nil)
145
141
  _assert_valid_url(callback)
146
142
  _assert_valid_topic(topic)
147
143
  _assert_valid_timestamp(timestamp) if timestamp
148
-
149
- data = { type: event, url: callback, timestamp: timestamp }
150
-
151
- response = _post("/topics/#{topic}") do |r|
152
- r.headers['Content-Type'] = 'application/json'
153
- r.body = Oj.dump(_stringify_keys data)
154
- end
155
- fail "event rejected (#{response.status})" unless response.success?
144
+ _backend.send_event(event, topic, callback, timestamp)
156
145
  end
157
146
 
158
147
  def _assert(condition, message)
159
148
  condition or raise ArgumentError.new(message)
160
149
  end
161
150
 
162
- def _http(method, path, &block)
163
- _conn.send(method, path, &block)
164
- end
165
-
166
- def _post(path, &block)
167
- _http(:post, path, &block)
168
- end
169
-
170
- def _get(path, &block)
171
- _http(:get, path, &block)
172
- end
173
-
174
- def _delete(path, &block)
175
- _http(:delete, path, &block)
176
- end
177
-
178
151
  def _conn
179
- @_conn ||= Faraday.new(@_url, ssl: { verify: @_verify_ssl }) do |f|
180
- f.request :retry, max: 2, interval: 100e-3, backoff_factor: 2
181
- f.request :basic_auth, @_uuid, 'x'
182
- f.adapter :typhoeus
152
+ @_conn ||= Client::Connection.new(@_options)
153
+ end
183
154
 
184
- f.options.timeout = @_timeout
185
- f.options.open_timeout = @_timeout
186
- end
155
+ def _backend
156
+ @_worker ||= @_backend_type.configure(@_options)
187
157
  end
188
158
  end
189
159
  end
data/spec/client_spec.rb CHANGED
@@ -2,6 +2,7 @@ require 'spec_helper'
2
2
  require 'routemaster/client'
3
3
  require 'routemaster/topic'
4
4
  require 'webmock/rspec'
5
+ require 'sidekiq/testing'
5
6
 
6
7
  describe Routemaster::Client do
7
8
  let(:options) {{
@@ -39,6 +40,12 @@ describe Routemaster::Client do
39
40
  expect { subject }.to raise_error(ArgumentError)
40
41
  end
41
42
 
43
+ it 'fails with an invalid worker_type' do
44
+ Jeff = double
45
+ options[:backend_type] = Jeff
46
+ expect { subject }.to raise_error(ArgumentError)
47
+ end
48
+
42
49
  context 'when connection fails' do
43
50
  before do
44
51
  stub_request(:any, %r{^https://bus.example.com}).
@@ -167,24 +174,58 @@ describe Routemaster::Client do
167
174
  end
168
175
  end
169
176
 
170
- describe '#created' do
171
- let(:event) { 'created' }
172
- it_behaves_like 'an event sender'
173
- end
177
+ context "With no background worker specified" do
178
+ describe '#created' do
179
+ let(:event) { 'created' }
180
+ it_behaves_like 'an event sender'
181
+ end
174
182
 
175
- describe '#updated' do
176
- let(:event) { 'updated' }
177
- it_behaves_like 'an event sender'
178
- end
183
+ describe '#updated' do
184
+ let(:event) { 'updated' }
185
+ it_behaves_like 'an event sender'
186
+ end
187
+
188
+ describe '#deleted' do
189
+ let(:event) { 'deleted' }
190
+ it_behaves_like 'an event sender'
191
+ end
179
192
 
180
- describe '#deleted' do
181
- let(:event) { 'deleted' }
182
- it_behaves_like 'an event sender'
193
+ describe '#noop' do
194
+ let(:event) { 'noop' }
195
+ it_behaves_like 'an event sender'
196
+ end
183
197
  end
184
198
 
185
- describe '#noop' do
186
- let(:event) { 'noop' }
187
- it_behaves_like 'an event sender'
199
+ context "With the sidekiq back end" do
200
+ before do
201
+ options[:backend_type] = Routemaster::Client::Backends::Sidekiq
202
+ end
203
+
204
+ around do |example|
205
+ Sidekiq::Testing.inline! do
206
+ example.run
207
+ end
208
+ end
209
+
210
+ describe '#created' do
211
+ let(:event) { 'created' }
212
+ it_behaves_like 'an event sender'
213
+ end
214
+
215
+ describe '#updated' do
216
+ let(:event) { 'updated' }
217
+ it_behaves_like 'an event sender'
218
+ end
219
+
220
+ describe '#deleted' do
221
+ let(:event) { 'deleted' }
222
+ it_behaves_like 'an event sender'
223
+ end
224
+
225
+ describe '#noop' do
226
+ let(:event) { 'noop' }
227
+ it_behaves_like 'an event sender'
228
+ end
188
229
  end
189
230
 
190
231
  describe '#subscribe' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: routemaster-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julien Letessier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-07 00:00:00.000000000 Z
11
+ date: 2016-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: typhoeus
@@ -86,6 +86,11 @@ files:
86
86
  - Rakefile
87
87
  - routemaster-client.gemspec
88
88
  - routemaster/client.rb
89
+ - routemaster/client/backends.rb
90
+ - routemaster/client/backends/sidekiq.rb
91
+ - routemaster/client/backends/sidekiq/worker.rb
92
+ - routemaster/client/backends/synchronous.rb
93
+ - routemaster/client/connection.rb
89
94
  - routemaster/client/version.rb
90
95
  - routemaster/receiver.rb
91
96
  - routemaster/topic.rb