message_bus 3.3.7 → 4.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 +4 -4
- data/.eslintrc.js +1 -8
- data/.github/workflows/ci.yml +50 -20
- data/.prettierrc +1 -0
- data/CHANGELOG +99 -46
- data/README.md +31 -53
- data/Rakefile +22 -22
- data/docker-compose.yml +1 -1
- data/lib/message_bus/backends/base.rb +14 -0
- data/lib/message_bus/backends/memory.rb +13 -0
- data/lib/message_bus/backends/postgres.rb +55 -22
- data/lib/message_bus/backends/redis.rb +17 -1
- data/lib/message_bus/client.rb +26 -22
- data/lib/message_bus/distributed_cache.rb +1 -0
- data/lib/message_bus/rack/middleware.rb +0 -6
- data/lib/message_bus/rack/thin_ext.rb +1 -0
- data/lib/message_bus/version.rb +1 -1
- data/lib/message_bus.rb +53 -71
- data/message_bus.gemspec +4 -3
- data/package.json +2 -5
- data/spec/helpers.rb +6 -1
- data/spec/lib/fake_async_middleware.rb +1 -0
- data/spec/lib/message_bus/backend_spec.rb +20 -3
- data/spec/lib/message_bus/client_spec.rb +1 -0
- data/spec/lib/message_bus/connection_manager_spec.rb +4 -0
- data/spec/lib/message_bus/multi_process_spec.rb +21 -10
- data/spec/lib/message_bus/rack/middleware_spec.rb +2 -49
- data/spec/lib/message_bus/timer_thread_spec.rb +1 -5
- data/spec/lib/message_bus_spec.rb +12 -3
- data/spec/performance/backlog.rb +80 -0
- data/spec/performance/publish.rb +4 -4
- data/spec/spec_helper.rb +1 -1
- data/vendor/assets/javascripts/message-bus-ajax.js +38 -0
- data/vendor/assets/javascripts/message-bus.js +549 -0
- metadata +8 -31
- data/assets/application.jsx +0 -121
- data/assets/babel.min.js +0 -25
- data/assets/react-dom.js +0 -19851
- data/assets/react.js +0 -3029
- data/examples/diagnostics/Gemfile +0 -6
- data/examples/diagnostics/config.ru +0 -22
- data/lib/message_bus/diagnostics.rb +0 -62
- data/lib/message_bus/rack/diagnostics.rb +0 -120
data/lib/message_bus.rb
CHANGED
@@ -7,9 +7,7 @@ require_relative "message_bus/version"
|
|
7
7
|
require_relative "message_bus/message"
|
8
8
|
require_relative "message_bus/client"
|
9
9
|
require_relative "message_bus/connection_manager"
|
10
|
-
require_relative "message_bus/diagnostics"
|
11
10
|
require_relative "message_bus/rack/middleware"
|
12
|
-
require_relative "message_bus/rack/diagnostics"
|
13
11
|
require_relative "message_bus/timer_thread"
|
14
12
|
require_relative "message_bus/codec/base"
|
15
13
|
require_relative "message_bus/backends"
|
@@ -41,21 +39,10 @@ module MessageBus::Implementation
|
|
41
39
|
def initialize
|
42
40
|
@config = {}
|
43
41
|
@mutex = Synchronizer.new
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
def cache_assets=(val)
|
49
|
-
configure(cache_assets: val)
|
50
|
-
end
|
51
|
-
|
52
|
-
# @return [Boolean] whether or not to cache static assets for the diagnostics pages
|
53
|
-
def cache_assets
|
54
|
-
if defined? @config[:cache_assets]
|
55
|
-
@config[:cache_assets]
|
56
|
-
else
|
57
|
-
true
|
58
|
-
end
|
42
|
+
@off = false
|
43
|
+
@destroyed = false
|
44
|
+
@timer_thread = nil
|
45
|
+
@subscriber_thread = nil
|
59
46
|
end
|
60
47
|
|
61
48
|
# @param [Logger] logger a logger object to be used by the bus
|
@@ -293,15 +280,20 @@ module MessageBus::Implementation
|
|
293
280
|
@config[:transport_codec] ||= MessageBus::Codec::Json.new
|
294
281
|
end
|
295
282
|
|
296
|
-
# @param [MessageBus::Backend::Base]
|
283
|
+
# @param [MessageBus::Backend::Base] backend_instance A configured backend
|
297
284
|
# @return [void]
|
285
|
+
def backend_instance=(backend_instance)
|
286
|
+
configure(backend_instance: backend_instance)
|
287
|
+
end
|
288
|
+
|
298
289
|
def reliable_pub_sub=(pub_sub)
|
299
|
-
|
290
|
+
logger.warn "MessageBus.reliable_pub_sub= is deprecated, use MessageBus.backend_instance= instead."
|
291
|
+
self.backend_instance = pub_sub
|
300
292
|
end
|
301
293
|
|
302
294
|
# @return [MessageBus::Backend::Base] the configured backend. If not
|
303
295
|
# explicitly set, will be loaded based on the configuration provided.
|
304
|
-
def
|
296
|
+
def backend_instance
|
305
297
|
@mutex.synchronize do
|
306
298
|
return nil if @destroyed
|
307
299
|
|
@@ -309,7 +301,7 @@ module MessageBus::Implementation
|
|
309
301
|
# passed to backend.
|
310
302
|
logger
|
311
303
|
|
312
|
-
@config[:
|
304
|
+
@config[:backend_instance] ||= begin
|
313
305
|
@config[:backend_options] ||= {}
|
314
306
|
require "message_bus/backends/#{backend}"
|
315
307
|
MessageBus::BACKENDS[backend].new @config
|
@@ -317,17 +309,16 @@ module MessageBus::Implementation
|
|
317
309
|
end
|
318
310
|
end
|
319
311
|
|
312
|
+
def reliable_pub_sub
|
313
|
+
logger.warn "MessageBus.reliable_pub_sub is deprecated, use MessageBus.backend_instance instead."
|
314
|
+
backend_instance
|
315
|
+
end
|
316
|
+
|
320
317
|
# @return [Symbol] the name of the backend implementation configured
|
321
318
|
def backend
|
322
319
|
@config[:backend] || :redis
|
323
320
|
end
|
324
321
|
|
325
|
-
# Enables diagnostics tracking
|
326
|
-
# @return [void]
|
327
|
-
def enable_diagnostics
|
328
|
-
MessageBus::Diagnostics.enable(self)
|
329
|
-
end
|
330
|
-
|
331
322
|
# Publishes a message to a channel
|
332
323
|
#
|
333
324
|
# @param [String] channel the name of the channel to which the message should be published
|
@@ -394,7 +385,7 @@ module MessageBus::Implementation
|
|
394
385
|
end
|
395
386
|
|
396
387
|
encoded_channel_name = encode_channel_name(channel, site_id)
|
397
|
-
|
388
|
+
backend_instance.publish(encoded_channel_name, encoded_data, channel_opts)
|
398
389
|
end
|
399
390
|
|
400
391
|
# Subscribe to messages. Each message will be delivered by yielding to the
|
@@ -410,9 +401,9 @@ module MessageBus::Implementation
|
|
410
401
|
# @return [void]
|
411
402
|
def blocking_subscribe(channel = nil, &blk)
|
412
403
|
if channel
|
413
|
-
|
404
|
+
backend_instance.subscribe(encode_channel_name(channel), &blk)
|
414
405
|
else
|
415
|
-
|
406
|
+
backend_instance.global_subscribe(&blk)
|
416
407
|
end
|
417
408
|
end
|
418
409
|
|
@@ -491,9 +482,9 @@ module MessageBus::Implementation
|
|
491
482
|
def backlog(channel = nil, last_id = nil, site_id = nil)
|
492
483
|
old =
|
493
484
|
if channel
|
494
|
-
|
485
|
+
backend_instance.backlog(encode_channel_name(channel, site_id), last_id)
|
495
486
|
else
|
496
|
-
|
487
|
+
backend_instance.global_backlog(last_id)
|
497
488
|
end
|
498
489
|
|
499
490
|
old.each do |m|
|
@@ -509,7 +500,19 @@ module MessageBus::Implementation
|
|
509
500
|
#
|
510
501
|
# @return [Integer] the channel-specific ID of the last message published to the given channel
|
511
502
|
def last_id(channel, site_id = nil)
|
512
|
-
|
503
|
+
backend_instance.last_id(encode_channel_name(channel, site_id))
|
504
|
+
end
|
505
|
+
|
506
|
+
# Get the ID of the last message published on multiple channels
|
507
|
+
#
|
508
|
+
# @param [Array<String>] channels - array of channels to fetch
|
509
|
+
# @param [String] site_id - the ID of the site by which to filter
|
510
|
+
#
|
511
|
+
# @return [Hash] the channel-specific IDs of the last message published to each requested channel
|
512
|
+
def last_ids(*channels, site_id: nil)
|
513
|
+
encoded_channel_names = channels.map { |c| encode_channel_name(c, site_id) }
|
514
|
+
ids = backend_instance.last_ids(*encoded_channel_names)
|
515
|
+
channels.zip(ids).to_h
|
513
516
|
end
|
514
517
|
|
515
518
|
# Get the last message published on a channel
|
@@ -532,7 +535,8 @@ module MessageBus::Implementation
|
|
532
535
|
def destroy
|
533
536
|
return if @destroyed
|
534
537
|
|
535
|
-
|
538
|
+
backend_instance.global_unsubscribe
|
539
|
+
backend_instance.destroy
|
536
540
|
|
537
541
|
@mutex.synchronize do
|
538
542
|
return if @destroyed
|
@@ -550,7 +554,7 @@ module MessageBus::Implementation
|
|
550
554
|
# scheduled tasks.
|
551
555
|
# @return [void]
|
552
556
|
def after_fork
|
553
|
-
|
557
|
+
backend_instance.after_fork
|
554
558
|
ensure_subscriber_thread
|
555
559
|
# will ensure timer is running
|
556
560
|
timer.queue {}
|
@@ -559,12 +563,12 @@ module MessageBus::Implementation
|
|
559
563
|
# @return [Boolean] whether or not the server is actively listening for
|
560
564
|
# publications on the bus
|
561
565
|
def listening?
|
562
|
-
@subscriber_thread
|
566
|
+
@subscriber_thread&.alive?
|
563
567
|
end
|
564
568
|
|
565
569
|
# (see MessageBus::Backend::Base#reset!)
|
566
570
|
def reset!
|
567
|
-
|
571
|
+
backend_instance.reset! if backend_instance
|
568
572
|
end
|
569
573
|
|
570
574
|
# @return [MessageBus::TimerThread] the timer thread used for triggering
|
@@ -692,12 +696,6 @@ module MessageBus::Implementation
|
|
692
696
|
@subscriptions[site_id][channel] << blk
|
693
697
|
ensure_subscriber_thread
|
694
698
|
|
695
|
-
attempts = 100
|
696
|
-
while attempts > 0 && !reliable_pub_sub.subscribed
|
697
|
-
sleep 0.001
|
698
|
-
attempts -= 1
|
699
|
-
end
|
700
|
-
|
701
699
|
raise MessageBus::BusDestroyed if @destroyed
|
702
700
|
|
703
701
|
blk
|
@@ -715,10 +713,17 @@ module MessageBus::Implementation
|
|
715
713
|
|
716
714
|
def ensure_subscriber_thread
|
717
715
|
@mutex.synchronize do
|
718
|
-
return if
|
716
|
+
return if @destroyed
|
717
|
+
next if @subscriber_thread&.alive?
|
719
718
|
|
720
719
|
@subscriber_thread = new_subscriber_thread
|
721
720
|
end
|
721
|
+
|
722
|
+
attempts = 100
|
723
|
+
while attempts > 0 && !backend_instance.subscribed
|
724
|
+
sleep 0.001
|
725
|
+
attempts -= 1
|
726
|
+
end
|
722
727
|
end
|
723
728
|
|
724
729
|
MIN_KEEPALIVE = 20
|
@@ -739,34 +744,11 @@ module MessageBus::Implementation
|
|
739
744
|
if !@destroyed && thread.alive? && keepalive_interval > MIN_KEEPALIVE
|
740
745
|
|
741
746
|
publish("/__mb_keepalive__/", Process.pid, user_ids: [-1])
|
742
|
-
# going for x3 keepalives missed for a restart, need to ensure this only very rarely happens
|
743
|
-
# note: after_fork will sort out a bad @last_message date, but thread will be dead anyway
|
744
747
|
if (Time.now - (@last_message || Time.now)) > keepalive_interval * 3
|
745
|
-
logger.warn "Global messages on #{Process.pid} timed out,
|
746
|
-
# No other clean way to remove this thread, its listening on a socket
|
747
|
-
# no data is arriving
|
748
|
-
#
|
749
|
-
# In production we see this kind of situation ... sometimes ... when there is
|
750
|
-
# a VRRP failover, or weird networking condition
|
751
|
-
pid = Process.pid
|
752
|
-
|
753
|
-
# do the best we can to terminate self cleanly
|
754
|
-
fork do
|
755
|
-
Process.kill('TERM', pid)
|
756
|
-
sleep 10
|
757
|
-
begin
|
758
|
-
Process.kill('KILL', pid)
|
759
|
-
rescue Errno::ESRCH
|
760
|
-
logger.warn "#{Process.pid} successfully terminated by `TERM` signal."
|
761
|
-
end
|
762
|
-
end
|
763
|
-
|
764
|
-
sleep 10
|
765
|
-
Process.kill('KILL', pid)
|
766
|
-
|
767
|
-
else
|
768
|
-
timer.queue(keepalive_interval, &blk) if keepalive_interval > MIN_KEEPALIVE
|
748
|
+
logger.warn "Global messages on #{Process.pid} timed out, message bus is no longer functioning correctly"
|
769
749
|
end
|
750
|
+
|
751
|
+
timer.queue(keepalive_interval, &blk) if keepalive_interval > MIN_KEEPALIVE
|
770
752
|
end
|
771
753
|
end
|
772
754
|
|
@@ -778,7 +760,7 @@ module MessageBus::Implementation
|
|
778
760
|
def global_subscribe_thread
|
779
761
|
# pretend we just got a message
|
780
762
|
@last_message = Time.now
|
781
|
-
|
763
|
+
backend_instance.global_subscribe do |msg|
|
782
764
|
begin
|
783
765
|
@last_message = Time.now
|
784
766
|
decode_message!(msg)
|
data/message_bus.gemspec
CHANGED
@@ -9,9 +9,8 @@ Gem::Specification.new do |gem|
|
|
9
9
|
gem.summary = %q{}
|
10
10
|
gem.homepage = "https://github.com/discourse/message_bus"
|
11
11
|
gem.license = "MIT"
|
12
|
-
gem.files = `git ls-files`.split($\)
|
13
|
-
|
14
|
-
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
12
|
+
gem.files = `git ls-files`.split($\) +
|
13
|
+
["vendor/assets/javascripts/message-bus.js", "vendor/assets/javascripts/message-bus-ajax.js"]
|
15
14
|
gem.name = "message_bus"
|
16
15
|
gem.require_paths = ["lib"]
|
17
16
|
gem.version = MessageBus::VERSION
|
@@ -19,9 +18,11 @@ Gem::Specification.new do |gem|
|
|
19
18
|
|
20
19
|
gem.add_runtime_dependency 'rack', '>= 1.1.3'
|
21
20
|
|
21
|
+
# Optional runtime dependencies
|
22
22
|
gem.add_development_dependency 'redis'
|
23
23
|
gem.add_development_dependency 'pg'
|
24
24
|
gem.add_development_dependency 'concurrent-ruby' # for distributed-cache
|
25
|
+
|
25
26
|
gem.add_development_dependency 'minitest'
|
26
27
|
gem.add_development_dependency 'minitest-hooks'
|
27
28
|
gem.add_development_dependency 'minitest-global_expectations'
|
data/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "message-bus-client",
|
3
|
-
"version": "
|
3
|
+
"version": "0.0.0-version-placeholder",
|
4
4
|
"description": "A message bus client in Javascript",
|
5
5
|
"main": "assets/message-bus.js",
|
6
6
|
"keywords": [
|
@@ -12,10 +12,7 @@
|
|
12
12
|
],
|
13
13
|
"jsnext:main": "assets/message-bus.js",
|
14
14
|
"module": "assets/message-bus.js",
|
15
|
-
"repository":
|
16
|
-
"type": "git",
|
17
|
-
"url": "git+https://github.com/discourse/message_bus.git"
|
18
|
-
},
|
15
|
+
"repository": "https://github.com/discourse/message_bus",
|
19
16
|
"author": "Sam Saffron, Robin Ward",
|
20
17
|
"license": "MIT",
|
21
18
|
"bugs": {
|
data/spec/helpers.rb
CHANGED
@@ -25,7 +25,12 @@ def test_config_for_backend(backend)
|
|
25
25
|
when :redis
|
26
26
|
config[:url] = ENV['REDISURL']
|
27
27
|
when :postgres
|
28
|
-
config[:backend_options] = {
|
28
|
+
config[:backend_options] = {
|
29
|
+
host: ENV['PGHOST'],
|
30
|
+
user: ENV['PGUSER'] || ENV['USER'],
|
31
|
+
password: ENV['PGPASSWORD'],
|
32
|
+
dbname: ENV['PGDATABASE'] || 'message_bus_test'
|
33
|
+
}
|
29
34
|
end
|
30
35
|
config
|
31
36
|
end
|
@@ -3,13 +3,14 @@
|
|
3
3
|
require_relative '../../spec_helper'
|
4
4
|
require 'message_bus'
|
5
5
|
|
6
|
-
describe
|
6
|
+
describe BACKEND_CLASS do
|
7
7
|
before do
|
8
|
-
@bus =
|
8
|
+
@bus = BACKEND_CLASS.new(test_config_for_backend(CURRENT_BACKEND))
|
9
9
|
end
|
10
10
|
|
11
11
|
after do
|
12
12
|
@bus.reset!
|
13
|
+
@bus.destroy
|
13
14
|
end
|
14
15
|
|
15
16
|
describe "API parity" do
|
@@ -29,7 +30,7 @@ describe PUB_SUB_CLASS do
|
|
29
30
|
end
|
30
31
|
|
31
32
|
it "should initialize with max_backlog_size" do
|
32
|
-
|
33
|
+
BACKEND_CLASS.new({}, 2000).max_backlog_size.must_equal 2000
|
33
34
|
end
|
34
35
|
|
35
36
|
it "should truncate channels correctly" do
|
@@ -90,6 +91,22 @@ describe PUB_SUB_CLASS do
|
|
90
91
|
@bus.last_id("/foo").must_equal 1
|
91
92
|
end
|
92
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
|
+
|
93
110
|
it "can set backlog age" do
|
94
111
|
@bus.max_backlog_age = 1
|
95
112
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require_relative '../../spec_helper'
|
4
4
|
require 'message_bus'
|
5
5
|
|
6
|
-
describe
|
6
|
+
describe BACKEND_CLASS do
|
7
7
|
def self.error!
|
8
8
|
@error = true
|
9
9
|
end
|
@@ -13,18 +13,20 @@ describe PUB_SUB_CLASS do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def new_bus
|
16
|
-
|
16
|
+
BACKEND_CLASS.new(test_config_for_backend(CURRENT_BACKEND).merge(db: 10))
|
17
17
|
end
|
18
18
|
|
19
19
|
def work_it
|
20
20
|
bus = new_bus
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
bus.subscribe("/echo", 0) do |msg|
|
22
|
+
if msg.data == "done"
|
23
|
+
bus.global_unsubscribe
|
24
|
+
else
|
25
|
+
bus.publish("/response", "#{msg.data}-#{Process.pid.to_s}")
|
26
|
+
end
|
26
27
|
end
|
27
28
|
ensure
|
29
|
+
bus.destroy
|
28
30
|
exit!(0)
|
29
31
|
end
|
30
32
|
|
@@ -44,12 +46,14 @@ describe PUB_SUB_CLASS do
|
|
44
46
|
test_never :memory
|
45
47
|
skip("previous error") if self.class.error?
|
46
48
|
GC.start
|
47
|
-
new_bus
|
49
|
+
bus = new_bus
|
50
|
+
bus.reset!
|
51
|
+
|
48
52
|
begin
|
49
53
|
pids = (1..10).map { spawn_child }
|
50
54
|
expected_responses = pids.map { |x| (0...10).map { |i| "0#{i}-#{x}" } }.flatten
|
51
55
|
unexpected_responses = []
|
52
|
-
|
56
|
+
|
53
57
|
t = Thread.new do
|
54
58
|
bus.subscribe("/response", 0) do |msg|
|
55
59
|
if expected_responses.include?(msg.data)
|
@@ -59,10 +63,14 @@ describe PUB_SUB_CLASS do
|
|
59
63
|
end
|
60
64
|
end
|
61
65
|
end
|
66
|
+
|
62
67
|
10.times { |i| bus.publish("/echo", "0#{i}") }
|
63
|
-
|
68
|
+
|
69
|
+
wait_for(2000) do
|
64
70
|
expected_responses.empty?
|
65
71
|
end
|
72
|
+
|
73
|
+
bus.publish("/echo", "done")
|
66
74
|
bus.global_unsubscribe
|
67
75
|
t.join
|
68
76
|
|
@@ -81,7 +89,10 @@ describe PUB_SUB_CLASS do
|
|
81
89
|
Process.wait(pid)
|
82
90
|
end
|
83
91
|
end
|
92
|
+
|
84
93
|
bus.global_unsubscribe
|
94
|
+
bus.reset!
|
95
|
+
bus.destroy
|
85
96
|
end
|
86
97
|
end
|
87
98
|
end
|
@@ -83,7 +83,7 @@ describe MessageBus::Rack::Middleware do
|
|
83
83
|
{ "FOO" => "BAR" }
|
84
84
|
end
|
85
85
|
|
86
|
-
Thread.new do
|
86
|
+
t = Thread.new do
|
87
87
|
wait_for(2000) { middleware.in_async? }
|
88
88
|
bus.publish "/foo", "םוֹלשָׁ"
|
89
89
|
end
|
@@ -96,6 +96,7 @@ describe MessageBus::Rack::Middleware do
|
|
96
96
|
parsed[0]["data"].must_equal "םוֹלשָׁ"
|
97
97
|
|
98
98
|
last_response.headers["FOO"].must_equal "BAR"
|
99
|
+
t.join
|
99
100
|
end
|
100
101
|
|
101
102
|
it "should timeout within its alloted slot" do
|
@@ -141,54 +142,6 @@ describe MessageBus::Rack::Middleware do
|
|
141
142
|
end
|
142
143
|
end
|
143
144
|
|
144
|
-
describe "diagnostics" do
|
145
|
-
it "should return a 403 if an unauthorized user attempts to get at the _diagnostics path" do
|
146
|
-
get "/message-bus/_diagnostics"
|
147
|
-
last_response.status.must_equal 403
|
148
|
-
end
|
149
|
-
|
150
|
-
it "should get a 200 with html for an authorized user" do
|
151
|
-
def @bus.is_admin_lookup
|
152
|
-
proc { |_| true }
|
153
|
-
end
|
154
|
-
|
155
|
-
get "/message-bus/_diagnostics"
|
156
|
-
last_response.status.must_equal 200
|
157
|
-
end
|
158
|
-
|
159
|
-
describe "with an altered base_route" do
|
160
|
-
let(:base_route) { "/base/route/" }
|
161
|
-
|
162
|
-
it "should get a 200 with html for an authorized user" do
|
163
|
-
def @bus.is_admin_lookup
|
164
|
-
proc { |_| true }
|
165
|
-
end
|
166
|
-
|
167
|
-
get "/base/route/message-bus/_diagnostics"
|
168
|
-
last_response.status.must_equal 200
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
it "should get the script it asks for" do
|
173
|
-
def @bus.is_admin_lookup
|
174
|
-
proc { |_| true }
|
175
|
-
end
|
176
|
-
|
177
|
-
get "/message-bus/_diagnostics/assets/message-bus.js"
|
178
|
-
last_response.status.must_equal 200
|
179
|
-
last_response.content_type.must_equal "application/javascript;charset=UTF-8"
|
180
|
-
end
|
181
|
-
|
182
|
-
it "should return 404 for invalid assets path" do
|
183
|
-
def @bus.is_admin_lookup
|
184
|
-
proc { |_| true }
|
185
|
-
end
|
186
|
-
|
187
|
-
get "/message-bus/_diagnostics/assets/../Gemfile"
|
188
|
-
last_response.status.must_equal 404
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
145
|
describe "polling" do
|
193
146
|
before do
|
194
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(
|
63
|
+
wait_for(100) do
|
68
64
|
error
|
69
65
|
end
|
70
66
|
|
@@ -23,7 +23,8 @@ describe MessageBus do
|
|
23
23
|
@bus.off?.must_equal true
|
24
24
|
end
|
25
25
|
|
26
|
-
it "can call destroy
|
26
|
+
it "can call destroy multiple times" do
|
27
|
+
@bus.destroy
|
27
28
|
@bus.destroy
|
28
29
|
@bus.destroy
|
29
30
|
end
|
@@ -36,6 +37,14 @@ describe MessageBus do
|
|
36
37
|
@bus.after_fork
|
37
38
|
end
|
38
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
|
+
|
39
48
|
describe "#base_route=" do
|
40
49
|
it "adds leading and trailing slashes" do
|
41
50
|
@bus.base_route = "my/base/route"
|
@@ -106,7 +115,7 @@ describe MessageBus do
|
|
106
115
|
@bus.publish("/chuck", norris: true)
|
107
116
|
@bus.publish("/chuck", norris: true)
|
108
117
|
|
109
|
-
@bus.
|
118
|
+
@bus.backend_instance.reset!
|
110
119
|
|
111
120
|
@bus.publish("/chuck", yeager: true)
|
112
121
|
|
@@ -124,7 +133,7 @@ describe MessageBus do
|
|
124
133
|
@bus.publish("/chuck", norris: true)
|
125
134
|
@bus.publish("/chuck", norris: true)
|
126
135
|
|
127
|
-
@bus.
|
136
|
+
@bus.backend_instance.expire_all_backlogs!
|
128
137
|
|
129
138
|
@bus.publish("/chuck", yeager: true)
|
130
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
|