message_bus 3.3.7 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|