message_bus 2.2.0.pre.1 → 2.2.0.pre.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of message_bus might be problematic. Click here for more details.

@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MessageBus
4
- VERSION = "2.2.0.pre.1"
4
+ VERSION = "2.2.0.pre.2"
5
5
  end
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'message_bus'
@@ -0,0 +1,17 @@
1
+ require 'message_bus'
2
+
3
+ MessageBus.config[:backend] = :memory
4
+ MessageBus.long_polling_interval = 1000
5
+ use MessageBus::Rack::Middleware
6
+
7
+ run ->(env) do
8
+ if env["REQUEST_METHOD"] == "GET" && env["REQUEST_PATH"] == "/publish"
9
+ payload = { hello: "world" }
10
+
11
+ ["/test", "/test2"].each do |channel|
12
+ MessageBus.publish(channel, payload)
13
+ end
14
+ end
15
+
16
+ [200, { "Content-Type" => "text/html" }, ["Howdy"]]
17
+ end
@@ -0,0 +1,19 @@
1
+ def wait_for(timeout_milliseconds = 2000)
2
+ timeout = (timeout_milliseconds + 0.0) / 1000
3
+ finish = Time.now + timeout
4
+
5
+ Thread.new do
6
+ sleep(0.001) while Time.now < finish && !yield
7
+ end.join
8
+ end
9
+
10
+ def test_config_for_backend(backend)
11
+ config = { backend: backend }
12
+ case backend
13
+ when :redis
14
+ config[:url] = ENV['REDISURL']
15
+ when :postgres
16
+ config[:backend_options] = { host: ENV['PGHOST'], user: ENV['PGUSER'] || ENV['USER'], password: ENV['PGPASSWORD'], dbname: ENV['PGDATABASE'] || 'message_bus_test' }
17
+ end
18
+ config
19
+ end
@@ -0,0 +1,197 @@
1
+ require_relative '../spec_helper'
2
+ require 'message_bus/http_client'
3
+
4
+ describe MessageBus::HTTPClient do
5
+ let(:base_url) { "http://0.0.0.0:9292" }
6
+ let(:client) { MessageBus::HTTPClient.new(base_url) }
7
+ let(:headers) { client.send(:headers) }
8
+ let(:channel) { "/test" }
9
+ let(:channel2) { "/test2" }
10
+ let(:stats) { client.stats }
11
+
12
+ def publish_message
13
+ response = Net::HTTP.get_response(URI("#{base_url}/publish"))
14
+ assert_equal("200", response.code)
15
+ end
16
+
17
+ before do
18
+ @threads = Thread.list
19
+ end
20
+
21
+ after do
22
+ new_threads = Thread.list - @threads
23
+ client.stop
24
+ new_threads.each(&:join)
25
+ end
26
+
27
+ describe '#start and #stop' do
28
+ it 'should be able to start and stop polling correctly' do
29
+ threads = Thread.list
30
+
31
+ assert_equal(MessageBus::HTTPClient::STOPPED, client.status)
32
+
33
+ client.start
34
+ new_threads = Thread.list - threads
35
+
36
+ assert_equal(1, new_threads.size)
37
+ assert_equal(MessageBus::HTTPClient::STARTED, client.status)
38
+
39
+ client.start
40
+
41
+ assert_equal(new_threads, Thread.list - threads)
42
+ end
43
+ end
44
+
45
+ describe '#subscribe' do
46
+ it 'should be able to subscribe to channels for messages' do
47
+ called = 0
48
+ called2 = 0
49
+
50
+ client.subscribe(channel, last_message_id: -1) do |data|
51
+ called += 1
52
+ assert_equal("world", data["hello"])
53
+ end
54
+
55
+ client.subscribe(channel2) do |data|
56
+ called2 += 1
57
+ assert_equal("world", data["hello"])
58
+ end
59
+
60
+ while called < 2 && called2 < 2
61
+ publish_message
62
+ sleep 0.05
63
+ end
64
+
65
+ while stats.success < 1
66
+ sleep 0.05
67
+ end
68
+
69
+ assert_equal(0, stats.failed)
70
+ end
71
+
72
+ describe 'supports including extra headers' do
73
+ let(:client) do
74
+ MessageBus::HTTPClient.new(base_url, headers: {
75
+ 'Dont-Chunk' => "true"
76
+ })
77
+ end
78
+
79
+ it 'should include the header in the request' do
80
+ called = 0
81
+
82
+ client.subscribe(channel) do |data|
83
+ called += 1
84
+ assert_equal("world", data["hello"])
85
+ end
86
+
87
+ while called < 2
88
+ publish_message
89
+ sleep 0.05
90
+ end
91
+ end
92
+ end
93
+
94
+ describe 'when chunked encoding is disabled' do
95
+ let(:client) do
96
+ MessageBus::HTTPClient.new(base_url, enable_chunked_encoding: false)
97
+ end
98
+
99
+ it 'should still be able to subscribe to channels for messages' do
100
+ called = 0
101
+
102
+ client.subscribe(channel) do |data|
103
+ called += 1
104
+ assert_equal("world", data["hello"])
105
+ end
106
+
107
+ while called < 2
108
+ publish_message
109
+ sleep 0.05
110
+ end
111
+ end
112
+ end
113
+
114
+ describe 'when enable_long_polling is disabled' do
115
+ let(:client) do
116
+ MessageBus::HTTPClient.new(base_url,
117
+ enable_long_polling: false,
118
+ background_callback_interval: 0.01)
119
+ end
120
+
121
+ it 'should still be able to subscribe to channels for messages' do
122
+ called = 0
123
+
124
+ client.subscribe(channel) do |data|
125
+ called += 1
126
+ assert_equal("world", data["hello"])
127
+ end
128
+
129
+ while called < 2
130
+ publish_message
131
+ sleep 0.05
132
+ end
133
+ end
134
+ end
135
+
136
+ describe 'when channel name is invalid' do
137
+ it 'should raise the right error' do
138
+ ["test", 1, :test].each do |invalid_channel|
139
+ assert_raises MessageBus::HTTPClient::InvalidChannel do
140
+ client.subscribe(invalid_channel)
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ describe 'when a block is not given' do
147
+ it 'should raise the right error' do
148
+ assert_raises MessageBus::HTTPClient::MissingBlock do
149
+ client.subscribe(channel)
150
+ end
151
+ end
152
+ end
153
+
154
+ describe 'with last_message_id' do
155
+ describe 'when invalid' do
156
+ it 'should subscribe from the latest message' do
157
+ client.subscribe(channel, last_message_id: 'haha') {}
158
+ assert_equal(-1, client.channels[channel].last_message_id)
159
+ end
160
+ end
161
+
162
+ describe 'when valid' do
163
+ it 'should subscribe from the right message' do
164
+ client.subscribe(channel, last_message_id: -2) {}
165
+ assert_equal(-2, client.channels[channel].last_message_id)
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ describe '#unsubscribe' do
172
+ it 'should be able to unsubscribe a channel' do
173
+ client.subscribe(channel) { raise "Not called" }
174
+ assert(client.channels[channel])
175
+
176
+ client.unsubscribe(channel)
177
+ assert_nil(client.channels[channel])
178
+ end
179
+
180
+ describe 'with callback' do
181
+ it 'should be able to unsubscribe a callback for a particular channel' do
182
+ callback = -> { raise "Not called" }
183
+ callback2 = -> { raise "Not called2" }
184
+
185
+ client.subscribe(channel, &callback)
186
+ client.subscribe(channel, &callback2)
187
+ assert_equal([callback, callback2], client.channels[channel].callbacks)
188
+
189
+ client.unsubscribe(channel, &callback)
190
+ assert_equal([callback2], client.channels[channel].callbacks)
191
+
192
+ client.unsubscribe(channel, &callback2)
193
+ assert_nil(client.channels[channel])
194
+ end
195
+ end
196
+ end
197
+ end
@@ -10,16 +10,24 @@ class FakeAsync
10
10
  @sent << val
11
11
  end
12
12
 
13
- def sent; @sent; end
13
+ def sent
14
+ @sent
15
+ end
14
16
 
15
- def done; @done = true; end
17
+ def done
18
+ @done = true
19
+ end
16
20
 
17
- def done?; @done; end
21
+ def done?
22
+ @done
23
+ end
18
24
  end
19
25
 
20
26
  class FakeTimer
21
27
  attr_accessor :cancelled
22
- def cancel; @cancelled = true; end
28
+ def cancel
29
+ @cancelled = true
30
+ end
23
31
  end
24
32
 
25
33
  describe MessageBus::ConnectionManager do
@@ -131,16 +131,24 @@ describe MessageBus::Rack::Middleware do
131
131
  end
132
132
 
133
133
  it "should get a 200 with html for an authorized user" do
134
- def @bus.is_admin_lookup; proc { |_| true } end
134
+
135
+ def @bus.is_admin_lookup
136
+ proc { |_| true }
137
+ end
138
+
135
139
  get "/message-bus/_diagnostics"
136
140
  last_response.status.must_equal 200
137
141
  end
138
142
 
139
143
  it "should get the script it asks for" do
140
- def @bus.is_admin_lookup; proc { |_| true } end
144
+
145
+ def @bus.is_admin_lookup
146
+ proc { |_| true }
147
+ end
148
+
141
149
  get "/message-bus/_diagnostics/assets/message-bus.js"
142
150
  last_response.status.must_equal 200
143
- last_response.content_type.must_equal "text/javascript;"
151
+ last_response.content_type.must_equal "application/javascript;charset=UTF-8"
144
152
  end
145
153
  end
146
154
 
@@ -0,0 +1,102 @@
1
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..', '..', 'lib')
2
+ require 'logger'
3
+ require 'benchmark'
4
+ require 'message_bus'
5
+
6
+ require_relative "../helpers"
7
+
8
+ backends = ENV['MESSAGE_BUS_BACKENDS'].split(",").map(&:to_sym)
9
+ channel = "/foo"
10
+ iterations = 10_000
11
+ results = []
12
+
13
+ puts "Running publication benchmark with #{iterations} iterations on backends: #{backends.inspect}"
14
+
15
+ benchmark_publication_only = lambda do |bm, backend|
16
+ bus = MessageBus::Instance.new
17
+ bus.configure(test_config_for_backend(backend))
18
+
19
+ bm.report("#{backend} - publication only") do
20
+ iterations.times { bus.publish(channel, "Hello world") }
21
+ end
22
+
23
+ bus.reset!
24
+ bus.destroy
25
+ end
26
+
27
+ benchmark_subscription_no_trimming = lambda do |bm, backend|
28
+ test_title = "#{backend} - subscription no trimming"
29
+
30
+ bus = MessageBus::Instance.new
31
+ bus.configure(test_config_for_backend(backend))
32
+
33
+ bus.reliable_pub_sub.max_backlog_size = iterations
34
+ bus.reliable_pub_sub.max_global_backlog_size = iterations
35
+
36
+ messages_received = 0
37
+ bus.after_fork
38
+ bus.subscribe(channel) do |_message|
39
+ messages_received += 1
40
+ end
41
+
42
+ bm.report(test_title) do
43
+ iterations.times { bus.publish(channel, "Hello world") }
44
+ wait_for(60000) { messages_received == iterations }
45
+ end
46
+
47
+ results << "[#{test_title}]: #{iterations} messages sent, #{messages_received} received, rate of #{(messages_received.to_f / iterations.to_f) * 100}%"
48
+
49
+ bus.reset!
50
+ bus.destroy
51
+ end
52
+
53
+ benchmark_subscription_with_trimming = lambda do |bm, backend|
54
+ test_title = "#{backend} - subscription with trimming"
55
+
56
+ bus = MessageBus::Instance.new
57
+ bus.configure(test_config_for_backend(backend))
58
+
59
+ bus.reliable_pub_sub.max_backlog_size = (iterations / 10)
60
+ bus.reliable_pub_sub.max_global_backlog_size = (iterations / 10)
61
+
62
+ messages_received = 0
63
+ bus.after_fork
64
+ bus.subscribe(channel) do |_message|
65
+ messages_received += 1
66
+ end
67
+
68
+ bm.report(test_title) do
69
+ iterations.times { bus.publish(channel, "Hello world") }
70
+ wait_for(60000) { messages_received == iterations }
71
+ end
72
+
73
+ results << "[#{test_title}]: #{iterations} messages sent, #{messages_received} received, rate of #{(messages_received.to_f / iterations.to_f) * 100}%"
74
+
75
+ bus.reset!
76
+ bus.destroy
77
+ end
78
+
79
+ puts
80
+ Benchmark.bm(60) do |bm|
81
+ backends.each do |backend|
82
+ benchmark_publication_only.call(bm, backend)
83
+ end
84
+
85
+ puts
86
+
87
+ backends.each do |backend|
88
+ benchmark_subscription_no_trimming.call(bm, backend)
89
+ end
90
+
91
+ results << nil
92
+ puts
93
+
94
+ backends.each do |backend|
95
+ benchmark_subscription_with_trimming.call(bm, backend)
96
+ end
97
+ end
98
+ puts
99
+
100
+ results.each do |result|
101
+ puts result
102
+ end
@@ -7,29 +7,14 @@ require 'message_bus'
7
7
  require 'minitest/autorun'
8
8
  require 'minitest/spec'
9
9
 
10
+ require_relative "helpers"
11
+
10
12
  backend = (ENV['MESSAGE_BUS_BACKEND'] || :redis).to_sym
11
- MESSAGE_BUS_CONFIG = { backend: backend }
13
+ MESSAGE_BUS_CONFIG = test_config_for_backend(backend)
12
14
  require "message_bus/backends/#{backend}"
13
15
  PUB_SUB_CLASS = MessageBus::BACKENDS.fetch(backend)
14
- case backend
15
- when :redis
16
- MESSAGE_BUS_CONFIG.merge!(url: ENV['REDISURL'])
17
- when :postgres
18
- MESSAGE_BUS_CONFIG.merge!(backend_options: { host: ENV['PGHOST'], user: ENV['PGUSER'] || ENV['USER'], password: ENV['PGPASSWORD'], dbname: ENV['PGDATABASE'] || 'message_bus_test' })
19
- end
20
16
  puts "Running with backend: #{backend}"
21
17
 
22
- def wait_for(timeout_milliseconds = 2000)
23
- timeout = (timeout_milliseconds + 0.0) / 1000
24
- finish = Time.now + timeout
25
-
26
- Thread.new do
27
- while Time.now < finish && !yield
28
- sleep(0.001)
29
- end
30
- end.join
31
- end
32
-
33
18
  def test_only(*backends)
34
19
  backend = MESSAGE_BUS_CONFIG[:backend]
35
20
  skip "Test doesn't apply to #{backend}" unless backends.include?(backend)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: message_bus
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0.pre.1
4
+ version: 2.2.0.pre.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-30 00:00:00.000000000 Z
11
+ date: 2018-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -61,7 +61,6 @@ extra_rdoc_files: []
61
61
  files:
62
62
  - ".gitignore"
63
63
  - ".rubocop.yml"
64
- - ".rubocop_todo.yml"
65
64
  - ".travis.yml"
66
65
  - CHANGELOG
67
66
  - Dockerfile
@@ -70,14 +69,13 @@ files:
70
69
  - LICENSE
71
70
  - README.md
72
71
  - Rakefile
73
- - assets/application.handlebars
74
- - assets/application.js
75
- - assets/ember.js
76
- - assets/handlebars.js
77
- - assets/index.handlebars
72
+ - assets/application.jsx
73
+ - assets/babel.min.js
78
74
  - assets/jquery-1.8.2.js
79
75
  - assets/message-bus-ajax.js
80
76
  - assets/message-bus.js
77
+ - assets/react-dom.js
78
+ - assets/react.js
81
79
  - docker-compose.yml
82
80
  - examples/bench/bench.lua
83
81
  - examples/bench/config.ru
@@ -89,6 +87,8 @@ files:
89
87
  - examples/chat/config.ru
90
88
  - examples/chat/docker_container/chat.yml
91
89
  - examples/chat/docker_container/update_chat
90
+ - examples/diagnostics/Gemfile
91
+ - examples/diagnostics/config.ru
92
92
  - examples/minimal/Gemfile
93
93
  - examples/minimal/config.ru
94
94
  - lib/message_bus.rb
@@ -102,6 +102,9 @@ files:
102
102
  - lib/message_bus/diagnostics.rb
103
103
  - lib/message_bus/distributed_cache.rb
104
104
  - lib/message_bus/em_ext.rb
105
+ - lib/message_bus/http_client.rb
106
+ - lib/message_bus/http_client/channel.rb
107
+ - lib/message_bus/http_client/version.rb
105
108
  - lib/message_bus/message.rb
106
109
  - lib/message_bus/rack/diagnostics.rb
107
110
  - lib/message_bus/rack/middleware.rb
@@ -114,6 +117,10 @@ files:
114
117
  - spec/assets/message-bus.spec.js
115
118
  - spec/assets/support/jasmine.yml
116
119
  - spec/assets/support/jasmine_helper.rb
120
+ - spec/fixtures/test/Gemfile
121
+ - spec/fixtures/test/config.ru
122
+ - spec/helpers.rb
123
+ - spec/integration/http_client_spec.rb
117
124
  - spec/lib/fake_async_middleware.rb
118
125
  - spec/lib/message_bus/assets/asset_encoding_spec.rb
119
126
  - spec/lib/message_bus/backend_spec.rb
@@ -124,6 +131,7 @@ files:
124
131
  - spec/lib/message_bus/rack/middleware_spec.rb
125
132
  - spec/lib/message_bus/timer_thread_spec.rb
126
133
  - spec/lib/message_bus_spec.rb
134
+ - spec/performance/publish.rb
127
135
  - spec/spec_helper.rb
128
136
  - vendor/assets/javascripts/.gitignore
129
137
  - vendor/assets/javascripts/message-bus-ajax.js
@@ -157,6 +165,10 @@ test_files:
157
165
  - spec/assets/message-bus.spec.js
158
166
  - spec/assets/support/jasmine.yml
159
167
  - spec/assets/support/jasmine_helper.rb
168
+ - spec/fixtures/test/Gemfile
169
+ - spec/fixtures/test/config.ru
170
+ - spec/helpers.rb
171
+ - spec/integration/http_client_spec.rb
160
172
  - spec/lib/fake_async_middleware.rb
161
173
  - spec/lib/message_bus/assets/asset_encoding_spec.rb
162
174
  - spec/lib/message_bus/backend_spec.rb
@@ -167,4 +179,5 @@ test_files:
167
179
  - spec/lib/message_bus/rack/middleware_spec.rb
168
180
  - spec/lib/message_bus/timer_thread_spec.rb
169
181
  - spec/lib/message_bus_spec.rb
182
+ - spec/performance/publish.rb
170
183
  - spec/spec_helper.rb