message_bus 3.3.8 → 4.2.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.
@@ -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
- );