message_bus 3.3.8 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,9 +3,9 @@
3
3
  require_relative '../../spec_helper'
4
4
  require 'message_bus'
5
5
 
6
- describe PUB_SUB_CLASS do
6
+ describe BACKEND_CLASS do
7
7
  before do
8
- @bus = PUB_SUB_CLASS.new(test_config_for_backend(CURRENT_BACKEND))
8
+ @bus = BACKEND_CLASS.new(test_config_for_backend(CURRENT_BACKEND))
9
9
  end
10
10
 
11
11
  after do
@@ -30,7 +30,7 @@ describe PUB_SUB_CLASS do
30
30
  end
31
31
 
32
32
  it "should initialize with max_backlog_size" do
33
- PUB_SUB_CLASS.new({}, 2000).max_backlog_size.must_equal 2000
33
+ BACKEND_CLASS.new({}, 2000).max_backlog_size.must_equal 2000
34
34
  end
35
35
 
36
36
  it "should truncate channels correctly" do
@@ -91,6 +91,22 @@ describe PUB_SUB_CLASS do
91
91
  @bus.last_id("/foo").must_equal 1
92
92
  end
93
93
 
94
+ it "should allow us to get multiple last_ids" do
95
+ @bus.last_ids("/foo", "/bar", "/foobar").must_equal [0, 0, 0]
96
+
97
+ @bus.publish("/foo", "one")
98
+ @bus.publish("/foo", "two")
99
+ @bus.publish("/foobar", "three")
100
+
101
+ @bus.last_ids("/foo", "/bar", "/foobar").must_equal(
102
+ [
103
+ @bus.last_id("/foo"),
104
+ @bus.last_id("/bar"),
105
+ @bus.last_id("/foobar")
106
+ ]
107
+ )
108
+ end
109
+
94
110
  it "can set backlog age" do
95
111
  @bus.max_backlog_age = 1
96
112
 
@@ -294,8 +310,6 @@ describe PUB_SUB_CLASS do
294
310
  end
295
311
 
296
312
  it "should support clear_every setting" do
297
- test_never :redis
298
-
299
313
  @bus.clear_every = 5
300
314
  @bus.max_global_backlog_size = 2
301
315
  @bus.publish "/foo", "11"
@@ -3,7 +3,7 @@
3
3
  require_relative '../../spec_helper'
4
4
  require 'message_bus'
5
5
 
6
- describe PUB_SUB_CLASS do
6
+ describe BACKEND_CLASS do
7
7
  def self.error!
8
8
  @error = true
9
9
  end
@@ -13,7 +13,7 @@ describe PUB_SUB_CLASS do
13
13
  end
14
14
 
15
15
  def new_bus
16
- PUB_SUB_CLASS.new(test_config_for_backend(CURRENT_BACKEND).merge(db: 10))
16
+ BACKEND_CLASS.new(test_config_for_backend(CURRENT_BACKEND).merge(db: 10))
17
17
  end
18
18
 
19
19
  def work_it
@@ -91,6 +91,7 @@ describe PUB_SUB_CLASS do
91
91
  end
92
92
 
93
93
  bus.global_unsubscribe
94
+ bus.reset!
94
95
  bus.destroy
95
96
  end
96
97
  end
@@ -142,54 +142,6 @@ describe MessageBus::Rack::Middleware do
142
142
  end
143
143
  end
144
144
 
145
- describe "diagnostics" do
146
- it "should return a 403 if an unauthorized user attempts to get at the _diagnostics path" do
147
- get "/message-bus/_diagnostics"
148
- last_response.status.must_equal 403
149
- end
150
-
151
- it "should get a 200 with html for an authorized user" do
152
- def @bus.is_admin_lookup
153
- proc { |_| true }
154
- end
155
-
156
- get "/message-bus/_diagnostics"
157
- last_response.status.must_equal 200
158
- end
159
-
160
- describe "with an altered base_route" do
161
- let(:base_route) { "/base/route/" }
162
-
163
- it "should get a 200 with html for an authorized user" do
164
- def @bus.is_admin_lookup
165
- proc { |_| true }
166
- end
167
-
168
- get "/base/route/message-bus/_diagnostics"
169
- last_response.status.must_equal 200
170
- end
171
- end
172
-
173
- it "should get the script it asks for" do
174
- def @bus.is_admin_lookup
175
- proc { |_| true }
176
- end
177
-
178
- get "/message-bus/_diagnostics/assets/message-bus.js"
179
- last_response.status.must_equal 200
180
- last_response.content_type.must_equal "application/javascript;charset=UTF-8"
181
- end
182
-
183
- it "should return 404 for invalid assets path" do
184
- def @bus.is_admin_lookup
185
- proc { |_| true }
186
- end
187
-
188
- get "/message-bus/_diagnostics/assets/../Gemfile"
189
- last_response.status.must_equal 404
190
- end
191
- end
192
-
193
145
  describe "polling" do
194
146
  before do
195
147
  @bus.long_polling_enabled = false
@@ -52,10 +52,6 @@ describe MessageBus::TimerThread do
52
52
  it "should call the error callback if something goes wrong" do
53
53
  error = nil
54
54
 
55
- @timer.queue do
56
- boom
57
- end
58
-
59
55
  @timer.on_error do |e|
60
56
  error = e
61
57
  end
@@ -64,7 +60,7 @@ describe MessageBus::TimerThread do
64
60
  boom
65
61
  end
66
62
 
67
- wait_for(10) do
63
+ wait_for(100) do
68
64
  error
69
65
  end
70
66
 
@@ -37,6 +37,14 @@ describe MessageBus do
37
37
  @bus.after_fork
38
38
  end
39
39
 
40
+ it "destroying immediately after `after_fork` does not lock" do
41
+ 10.times do
42
+ @bus.on
43
+ @bus.after_fork
44
+ @bus.destroy
45
+ end
46
+ end
47
+
40
48
  describe "#base_route=" do
41
49
  it "adds leading and trailing slashes" do
42
50
  @bus.base_route = "my/base/route"
@@ -107,7 +115,7 @@ describe MessageBus do
107
115
  @bus.publish("/chuck", norris: true)
108
116
  @bus.publish("/chuck", norris: true)
109
117
 
110
- @bus.reliable_pub_sub.reset!
118
+ @bus.backend_instance.reset!
111
119
 
112
120
  @bus.publish("/chuck", yeager: true)
113
121
 
@@ -125,7 +133,7 @@ describe MessageBus do
125
133
  @bus.publish("/chuck", norris: true)
126
134
  @bus.publish("/chuck", norris: true)
127
135
 
128
- @bus.reliable_pub_sub.expire_all_backlogs!
136
+ @bus.backend_instance.expire_all_backlogs!
129
137
 
130
138
  @bus.publish("/chuck", yeager: true)
131
139
 
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..', '..', 'lib')
4
+ require 'logger'
5
+ require 'benchmark'
6
+ require 'message_bus'
7
+
8
+ require_relative "../helpers"
9
+
10
+ backends = ENV['MESSAGE_BUS_BACKENDS'].split(",").map(&:to_sym)
11
+ channel = "/foo"
12
+ iterations = 10_000
13
+ results = []
14
+
15
+ puts "Running backlog benchmark with #{iterations} iterations on backends: #{backends.inspect}"
16
+
17
+ run_benchmark = lambda do |bm, backend|
18
+ bus = MessageBus::Instance.new
19
+ bus.configure(test_config_for_backend(backend))
20
+
21
+ bus.backend_instance.max_backlog_size = 100
22
+ bus.backend_instance.max_global_backlog_size = 1000
23
+
24
+ channel_names = 10.times.map { |i| "channel#{i}" }
25
+
26
+ 100.times do |i|
27
+ channel_names.each do |ch|
28
+ bus.publish(ch, { message_number_is: i })
29
+ end
30
+ end
31
+
32
+ last_ids = channel_names.map { |ch| [ch, bus.last_id(ch)] }.to_h
33
+
34
+ 1000.times do
35
+ # Warmup
36
+ client = MessageBus::Client.new(message_bus: bus)
37
+ channel_names.each { |ch| client.subscribe(ch, -1) }
38
+ client.backlog
39
+ end
40
+
41
+ bm.report("#{backend} - #backlog with no backlogs requested") do
42
+ iterations.times do
43
+ client = MessageBus::Client.new(message_bus: bus)
44
+ channel_names.each { |ch| client.subscribe(ch, -1) }
45
+ client.backlog
46
+ end
47
+ end
48
+
49
+ (0..5).each do |ch_i|
50
+ channels_with_messages = (ch_i) * 2
51
+
52
+ bm.report("#{backend} - #backlog when #{channels_with_messages}/10 channels have new messages") do
53
+ iterations.times do
54
+ client = MessageBus::Client.new(message_bus: bus)
55
+ channel_names.each_with_index do |ch, i|
56
+ client.subscribe(ch, last_ids[ch] + ((i < channels_with_messages) ? -1 : 0))
57
+ end
58
+ result = client.backlog
59
+ if result.length != channels_with_messages
60
+ raise "Result has #{result.length} messages. Expected #{channels_with_messages}"
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ bus.reset!
67
+ bus.destroy
68
+ end
69
+
70
+ puts
71
+
72
+ Benchmark.benchmark(" duration\n", 60, "%10.2rs\n", "") do |bm|
73
+ backends.each do |backend|
74
+ run_benchmark.call(bm, backend)
75
+ end
76
+ end
77
+ puts
78
+ results.each do |result|
79
+ puts result
80
+ end
@@ -9,7 +9,7 @@ require_relative "../helpers"
9
9
 
10
10
  backends = ENV['MESSAGE_BUS_BACKENDS'].split(",").map(&:to_sym)
11
11
  channel = "/foo"
12
- iterations = 10_000
12
+ iterations = 100_000
13
13
  results = []
14
14
 
15
15
  puts "Running publication benchmark with #{iterations} iterations on backends: #{backends.inspect}"
@@ -32,8 +32,8 @@ benchmark_subscription_no_trimming = lambda do |bm, backend|
32
32
  bus = MessageBus::Instance.new
33
33
  bus.configure(test_config_for_backend(backend))
34
34
 
35
- bus.reliable_pub_sub.max_backlog_size = iterations
36
- bus.reliable_pub_sub.max_global_backlog_size = iterations
35
+ bus.backend_instance.max_backlog_size = iterations
36
+ bus.backend_instance.max_global_backlog_size = iterations
37
37
 
38
38
  messages_received = 0
39
39
  bus.after_fork
@@ -58,8 +58,35 @@ benchmark_subscription_with_trimming = lambda do |bm, backend|
58
58
  bus = MessageBus::Instance.new
59
59
  bus.configure(test_config_for_backend(backend))
60
60
 
61
- bus.reliable_pub_sub.max_backlog_size = (iterations / 10)
62
- bus.reliable_pub_sub.max_global_backlog_size = (iterations / 10)
61
+ bus.backend_instance.max_backlog_size = (iterations / 10)
62
+ bus.backend_instance.max_global_backlog_size = (iterations / 10)
63
+
64
+ messages_received = 0
65
+ bus.after_fork
66
+ bus.subscribe(channel) do |_message|
67
+ messages_received += 1
68
+ end
69
+
70
+ bm.report(test_title) do
71
+ iterations.times { bus.publish(channel, "Hello world") }
72
+ wait_for(60000) { messages_received == iterations }
73
+ end
74
+
75
+ results << "[#{test_title}]: #{iterations} messages sent, #{messages_received} received, rate of #{(messages_received.to_f / iterations.to_f) * 100}%"
76
+
77
+ bus.reset!
78
+ bus.destroy
79
+ end
80
+
81
+ benchmark_subscription_with_trimming_and_clear_every = lambda do |bm, backend|
82
+ test_title = "#{backend} - subscription with trimming and clear_every=50"
83
+
84
+ bus = MessageBus::Instance.new
85
+ bus.configure(test_config_for_backend(backend))
86
+
87
+ bus.backend_instance.max_backlog_size = (iterations / 10)
88
+ bus.backend_instance.max_global_backlog_size = (iterations / 10)
89
+ bus.backend_instance.clear_every = 50
63
90
 
64
91
  messages_received = 0
65
92
  bus.after_fork
@@ -96,6 +123,10 @@ Benchmark.bm(60) do |bm|
96
123
  backends.each do |backend|
97
124
  benchmark_subscription_with_trimming.call(bm, backend)
98
125
  end
126
+
127
+ backends.each do |backend|
128
+ benchmark_subscription_with_trimming_and_clear_every.call(bm, backend)
129
+ end
99
130
  end
100
131
  puts
101
132
 
data/spec/spec_helper.rb CHANGED
@@ -14,7 +14,7 @@ require_relative "helpers"
14
14
  CURRENT_BACKEND = (ENV['MESSAGE_BUS_BACKEND'] || :redis).to_sym
15
15
 
16
16
  require "message_bus/backends/#{CURRENT_BACKEND}"
17
- PUB_SUB_CLASS = MessageBus::BACKENDS.fetch(CURRENT_BACKEND)
17
+ BACKEND_CLASS = MessageBus::BACKENDS.fetch(CURRENT_BACKEND)
18
18
 
19
19
  puts "Running with backend: #{CURRENT_BACKEND}"
20
20
 
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: 3.3.8
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-20 00:00:00.000000000 Z
11
+ date: 2022-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -282,13 +282,9 @@ files:
282
282
  - LICENSE
283
283
  - README.md
284
284
  - Rakefile
285
- - assets/application.jsx
286
- - assets/babel.min.js
287
285
  - assets/jquery-1.8.2.js
288
286
  - assets/message-bus-ajax.js
289
287
  - assets/message-bus.js
290
- - assets/react-dom.js
291
- - assets/react.js
292
288
  - bench/codecs/all_codecs.rb
293
289
  - bench/codecs/marshal.rb
294
290
  - bench/codecs/packed_string.rb
@@ -306,8 +302,6 @@ files:
306
302
  - examples/chat/config.ru
307
303
  - examples/chat/docker_container/chat.yml
308
304
  - examples/chat/docker_container/update_chat
309
- - examples/diagnostics/Gemfile
310
- - examples/diagnostics/config.ru
311
305
  - examples/minimal/Gemfile
312
306
  - examples/minimal/config.ru
313
307
  - lib/message_bus.rb
@@ -321,13 +315,11 @@ files:
321
315
  - lib/message_bus/codec/json.rb
322
316
  - lib/message_bus/codec/oj.rb
323
317
  - lib/message_bus/connection_manager.rb
324
- - lib/message_bus/diagnostics.rb
325
318
  - lib/message_bus/distributed_cache.rb
326
319
  - lib/message_bus/http_client.rb
327
320
  - lib/message_bus/http_client/channel.rb
328
321
  - lib/message_bus/http_client/version.rb
329
322
  - lib/message_bus/message.rb
330
- - lib/message_bus/rack/diagnostics.rb
331
323
  - lib/message_bus/rack/middleware.rb
332
324
  - lib/message_bus/rack/thin_ext.rb
333
325
  - lib/message_bus/rails/railtie.rb
@@ -352,6 +344,7 @@ files:
352
344
  - spec/lib/message_bus/rack/middleware_spec.rb
353
345
  - spec/lib/message_bus/timer_thread_spec.rb
354
346
  - spec/lib/message_bus_spec.rb
347
+ - spec/performance/backlog.rb
355
348
  - spec/performance/publish.rb
356
349
  - spec/spec_helper.rb
357
350
  - spec/support/jasmine-browser.json
@@ -381,23 +374,4 @@ rubygems_version: 3.1.6
381
374
  signing_key:
382
375
  specification_version: 4
383
376
  summary: ''
384
- test_files:
385
- - spec/assets/SpecHelper.js
386
- - spec/assets/message-bus.spec.js
387
- - spec/fixtures/test/Gemfile
388
- - spec/fixtures/test/config.ru
389
- - spec/helpers.rb
390
- - spec/integration/http_client_spec.rb
391
- - spec/lib/fake_async_middleware.rb
392
- - spec/lib/message_bus/assets/asset_encoding_spec.rb
393
- - spec/lib/message_bus/backend_spec.rb
394
- - spec/lib/message_bus/client_spec.rb
395
- - spec/lib/message_bus/connection_manager_spec.rb
396
- - spec/lib/message_bus/distributed_cache_spec.rb
397
- - spec/lib/message_bus/multi_process_spec.rb
398
- - spec/lib/message_bus/rack/middleware_spec.rb
399
- - spec/lib/message_bus/timer_thread_spec.rb
400
- - spec/lib/message_bus_spec.rb
401
- - spec/performance/publish.rb
402
- - spec/spec_helper.rb
403
- - spec/support/jasmine-browser.json
377
+ test_files: []
@@ -1,121 +0,0 @@
1
- 'use strict';
2
-
3
- class Process extends React.Component {
4
- hup() {
5
- fetch(
6
- `/message-bus/_diagnostics/hup/${this.props.hostname}/${this.props.pid}`,
7
- {
8
- method: 'POST'
9
- }
10
- );
11
- }
12
-
13
- render() {
14
- return (
15
- <tr>
16
- <td>{this.props.pid}</td>
17
- <td>{this.props.full_path}</td>
18
- <td>{this.props.hostname}</td>
19
- <td>{this.props.uptime} secs</td>
20
- <td><button onClick={this.hup.bind(this)}>HUP</button></td>
21
- </tr>
22
- );
23
- }
24
- };
25
-
26
- class DiagnosticsApp extends React.Component {
27
- constructor(props) {
28
- super(props);
29
- this.state = {processes: []};
30
- }
31
-
32
- componentDidMount() {
33
- MessageBus.start();
34
- this.ensureSubscribed();
35
- }
36
-
37
- discover() {
38
- this.ensureSubscribed();
39
-
40
- this.setState({discovering: true});
41
-
42
- var _this = this;
43
- fetch(
44
- "/message-bus/_diagnostics/discover",
45
- {
46
- method: "POST"
47
- }
48
- ).then(function() {
49
- _this.setState({discovering: false})
50
- });
51
- }
52
-
53
- ensureSubscribed() {
54
- if (this.state.subscribed) { return; }
55
-
56
- MessageBus.callbackInterval = 500;
57
-
58
- MessageBus.subscribe(
59
- "/_diagnostics/process-discovery",
60
- this.updateProcess.bind(this)
61
- );
62
-
63
- this.setState({subscribed: true});
64
- }
65
-
66
- updateProcess(data) {
67
- const _this = this;
68
- const processes = this.state.processes.filter(function(process) {
69
- return _this.processUniqueId(process) !== _this.processUniqueId(data);
70
- });
71
- this.setState({processes: processes.concat([data])});
72
- }
73
-
74
- processUniqueId(process) {
75
- return process.hostname + process.pid;
76
- }
77
-
78
- render() {
79
- let disabled = this.state.discovering ? "disabled" : null;
80
-
81
- let _this = this;
82
- let processes = this.state.processes.sort(function(a,b) {
83
- return _this.processUniqueId(a) < _this.processUniqueId(b) ? -1 : 1;
84
- });
85
-
86
- return (
87
- <div>
88
- <header>
89
- <h2>Message Bus Diagnostics</h2>
90
- </header>
91
-
92
- <div>
93
- <button onClick={this.discover.bind(this)} disabled={disabled}>Discover Processes</button>
94
-
95
- <table>
96
- <thead>
97
- <tr>
98
- <td>pid</td>
99
- <td>full_path</td>
100
- <td>hostname</td>
101
- <td>uptime</td>
102
- <td></td>
103
- </tr>
104
- </thead>
105
-
106
- <tbody>
107
- {processes.map(function(process, index){
108
- return <Process key={index} {...process} />;
109
- })}
110
- </tbody>
111
- </table>
112
- </div>
113
- </div>
114
- );
115
- }
116
- }
117
-
118
- ReactDOM.render(
119
- <DiagnosticsApp />,
120
- document.getElementById('app')
121
- );