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

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.

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