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.
data/Rakefile CHANGED
@@ -5,18 +5,16 @@ require 'bundler'
5
5
  require 'bundler/gem_tasks'
6
6
  require 'bundler/setup'
7
7
  require 'rubocop/rake_task'
8
+ require 'yard'
8
9
 
9
- RuboCop::RakeTask.new
10
+ Bundler.require(:default, :test)
10
11
 
11
- require 'yard'
12
+ RuboCop::RakeTask.new
12
13
  YARD::Rake::YardocTask.new
13
14
 
14
- desc "Generate documentation for Yard, and fail if there are any warnings"
15
- task :test_doc do
16
- sh "yard --fail-on-warning #{'--no-progress' if ENV['CI']}"
17
- end
18
-
19
- Bundler.require(:default, :test)
15
+ BACKENDS = Dir["lib/message_bus/backends/*.rb"].map { |file| file.match(%r{backends/(?<backend>.*).rb})[:backend] } - ["base"]
16
+ SPEC_FILES = Dir['spec/**/*_spec.rb']
17
+ INTEGRATION_FILES = Dir['spec/integration/**/*_spec.rb']
20
18
 
21
19
  module CustomBuild
22
20
  def build_gem
@@ -31,6 +29,11 @@ module Bundler
31
29
  end
32
30
  end
33
31
 
32
+ desc "Generate documentation for Yard, and fail if there are any warnings"
33
+ task :test_doc do
34
+ sh "yard --fail-on-warning #{'--no-progress' if ENV['CI']}"
35
+ end
36
+
34
37
  namespace :jasmine do
35
38
  desc "Run Jasmine tests in headless mode"
36
39
  task 'ci' do
@@ -40,18 +43,16 @@ namespace :jasmine do
40
43
  end
41
44
  end
42
45
 
43
- backends = Dir["lib/message_bus/backends/*.rb"].map { |file| file.match(%r{backends/(?<backend>.*).rb})[:backend] } - ["base"]
44
-
45
46
  namespace :spec do
46
- spec_files = Dir['spec/**/*_spec.rb']
47
- integration_files = Dir['spec/integration/**/*_spec.rb']
48
-
49
- backends.each do |backend|
47
+ BACKENDS.each do |backend|
50
48
  desc "Run tests on the #{backend} backend"
51
49
  task backend do
52
50
  begin
53
51
  ENV['MESSAGE_BUS_BACKEND'] = backend
54
- sh "#{FileUtils::RUBY} -e \"ARGV.each{|f| load f}\" #{(spec_files - integration_files).to_a.join(' ')}"
52
+ Rake::TestTask.new(backend) do |t|
53
+ t.test_files = SPEC_FILES - INTEGRATION_FILES
54
+ end
55
+ Rake::Task[backend].invoke
55
56
  ensure
56
57
  ENV.delete('MESSAGE_BUS_BACKEND')
57
58
  end
@@ -74,7 +75,10 @@ namespace :spec do
74
75
  ENV['MESSAGE_BUS_BACKEND'] = 'memory'
75
76
  pid = spawn("bundle exec puma -p 9292 spec/fixtures/test/config.ru")
76
77
  sleep 1 while port_available?(9292)
77
- sh "#{FileUtils::RUBY} -e \"ARGV.each{|f| load f}\" #{integration_files.to_a.join(' ')}"
78
+ Rake::TestTask.new(:integration) do |t|
79
+ t.test_files = INTEGRATION_FILES
80
+ end
81
+ Rake::Task[:integration].invoke
78
82
  ensure
79
83
  ENV.delete('MESSAGE_BUS_BACKEND')
80
84
  Process.kill('TERM', pid) if pid
@@ -83,12 +87,12 @@ namespace :spec do
83
87
  end
84
88
 
85
89
  desc "Run tests on all backends, plus client JS tests"
86
- task spec: backends.map { |backend| "spec:#{backend}" } + ["jasmine:ci", "spec:integration"]
90
+ task spec: BACKENDS.map { |backend| "spec:#{backend}" } + ["jasmine:ci", "spec:integration"]
87
91
 
88
92
  desc "Run performance benchmarks on all backends"
89
93
  task :performance do
90
94
  begin
91
- ENV['MESSAGE_BUS_BACKENDS'] = backends.join(",")
95
+ ENV['MESSAGE_BUS_BACKENDS'] = BACKENDS.join(",")
92
96
  sh "#{FileUtils::RUBY} -e \"ARGV.each{|f| load f}\" #{Dir['spec/performance/*.rb'].to_a.join(' ')}"
93
97
  ensure
94
98
  ENV.delete('MESSAGE_BUS_BACKENDS')
@@ -97,7 +101,3 @@ end
97
101
 
98
102
  desc "Run all tests, link checks and confirms documentation compiles without error"
99
103
  task default: [:spec, :rubocop, :test_doc]
100
-
101
- Rake::Task['release'].enhance do
102
- sh "yarn publish"
103
- end
data/docker-compose.yml CHANGED
@@ -36,7 +36,7 @@ services:
36
36
  example:
37
37
  build:
38
38
  context: .
39
- command: bash -c "cd examples/diagnostics && bundle install && bundle exec rackup --server puma --host 0.0.0.0"
39
+ command: bash -c "cd examples/chat && bundle install && bundle exec rackup --server puma --host 0.0.0.0"
40
40
  environment:
41
41
  BUNDLE_TO: /usr/local/bundle
42
42
  REDISURL: redis://redis:6379
@@ -118,6 +118,15 @@ module MessageBus
118
118
  raise ConcreteClassMustImplementError
119
119
  end
120
120
 
121
+ # Get the ID of the last message published on multiple channels
122
+ #
123
+ # @param [Array<String>] channels - array of channels to fetch
124
+ #
125
+ # @return [Array<Integer>] the channel-specific IDs of the last message published to each requested channel
126
+ def last_ids(*channels)
127
+ raise ConcreteClassMustImplementError
128
+ end
129
+
121
130
  # Get messages from a channel backlog
122
131
  #
123
132
  # @param [String] channel the name of the channel in question
@@ -244,6 +244,13 @@ module MessageBus
244
244
  client.max_id(channel)
245
245
  end
246
246
 
247
+ # (see Base#last_ids)
248
+ def last_ids(*channels)
249
+ channels.map do |c|
250
+ last_id(c)
251
+ end
252
+ end
253
+
247
254
  # (see Base#backlog)
248
255
  def backlog(channel, last_id = 0)
249
256
  items = client.backlog channel, last_id.to_i
@@ -45,6 +45,7 @@ module MessageBus
45
45
  @available = []
46
46
  @allocated = {}
47
47
  @subscribe_connection = nil
48
+ @subscribed = false
48
49
  @mutex = Mutex.new
49
50
  @pid = Process.pid
50
51
  end
@@ -131,6 +132,21 @@ module MessageBus
131
132
  end
132
133
  end
133
134
 
135
+ def max_ids(*channels)
136
+ block = proc do |pg_result|
137
+ ids = Array.new(channels.size, 0)
138
+ pg_result.ntuples.times do |i|
139
+ channel = pg_result.getvalue(i, 0)
140
+ max_id = pg_result.getvalue(i, 1)
141
+ channel_index = channels.index(channel)
142
+ ids[channel_index] = max_id.to_i
143
+ end
144
+ ids
145
+ end
146
+
147
+ hold { |conn| exec_prepared(conn, 'max_channel_ids', [PG::TextEncoder::Array.new.encode(channels)], &block) }
148
+ end
149
+
134
150
  def publish(channel, data)
135
151
  hold { |conn| exec_prepared(conn, 'publish', [channel, data]) }
136
152
  end
@@ -174,9 +190,16 @@ module MessageBus
174
190
  end
175
191
 
176
192
  def create_table(conn)
177
- conn.exec 'CREATE TABLE message_bus (id bigserial PRIMARY KEY, channel text NOT NULL, value text NOT NULL CHECK (octet_length(value) >= 2), added_at timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL)'
178
- conn.exec 'CREATE INDEX table_channel_id_index ON message_bus (channel, id)'
179
- conn.exec 'CREATE INDEX table_added_at_index ON message_bus (added_at)'
193
+ sync do
194
+ begin
195
+ conn.exec("SELECT 'message_bus'::regclass")
196
+ rescue PG::UndefinedTable
197
+ conn.exec 'CREATE TABLE message_bus (id bigserial PRIMARY KEY, channel text NOT NULL, value text NOT NULL CHECK (octet_length(value) >= 2), added_at timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL)'
198
+ conn.exec 'CREATE INDEX table_channel_id_index ON message_bus (channel, id)'
199
+ conn.exec 'CREATE INDEX table_added_at_index ON message_bus (added_at)'
200
+ end
201
+ end
202
+
180
203
  nil
181
204
  end
182
205
 
@@ -213,11 +236,7 @@ module MessageBus
213
236
  def new_pg_connection
214
237
  conn = raw_pg_connection
215
238
 
216
- begin
217
- conn.exec("SELECT 'message_bus'::regclass")
218
- rescue PG::UndefinedTable
219
- create_table(conn)
220
- end
239
+ create_table(conn)
221
240
 
222
241
  conn.exec 'PREPARE insert_message AS INSERT INTO message_bus (channel, value) VALUES ($1, $2) RETURNING id'
223
242
  conn.exec 'PREPARE clear_global_backlog AS DELETE FROM message_bus WHERE (id <= $1)'
@@ -227,6 +246,7 @@ module MessageBus
227
246
  conn.exec "PREPARE expire AS DELETE FROM message_bus WHERE added_at < CURRENT_TIMESTAMP - ($1::text || ' seconds')::interval"
228
247
  conn.exec 'PREPARE get_message AS SELECT value FROM message_bus WHERE ((channel = $1) AND (id = $2))'
229
248
  conn.exec 'PREPARE max_channel_id AS SELECT max(id) FROM message_bus WHERE (channel = $1)'
249
+ conn.exec 'PREPARE max_channel_ids AS SELECT channel, max(id) FROM message_bus WHERE (channel = ANY($1)) GROUP BY channel'
230
250
  conn.exec 'PREPARE max_id AS SELECT max(id) FROM message_bus'
231
251
  conn.exec 'PREPARE publish AS SELECT pg_notify($1, $2)'
232
252
 
@@ -259,6 +279,7 @@ module MessageBus
259
279
  @max_backlog_age = 604800
260
280
  @clear_every = config[:clear_every] || 1
261
281
  @mutex = Mutex.new
282
+ @client = nil
262
283
  end
263
284
 
264
285
  # Reconnects to Postgres; used after a process fork, typically triggered by a forking webserver
@@ -308,7 +329,12 @@ module MessageBus
308
329
  client.max_id(channel)
309
330
  end
310
331
 
311
- # (see Base#last_id)
332
+ # (see Base#last_ids)
333
+ def last_ids(*channels)
334
+ client.max_ids(*channels)
335
+ end
336
+
337
+ # (see Base#backlog)
312
338
  def backlog(channel, last_id = 0)
313
339
  items = client.backlog channel, last_id.to_i
314
340
 
@@ -30,8 +30,6 @@ module MessageBus
30
30
  # messages are removed (when no publication happens during this
31
31
  # time-frame).
32
32
  #
33
- # * `clear_every` is not a supported option for this backend.
34
- #
35
33
  # @see Base general information about message_bus backends
36
34
  class Redis < Base
37
35
  class BackLogOutOfOrder < StandardError
@@ -45,9 +43,11 @@ module MessageBus
45
43
  # @param [Hash] redis_config in addition to the options listed, see https://github.com/redis/redis-rb for other available options
46
44
  # @option redis_config [Logger] :logger a logger to which logs will be output
47
45
  # @option redis_config [Boolean] :enable_redis_logger (false) whether or not to enable logging by the underlying Redis library
46
+ # @option redis_config [Integer] :clear_every (1) the interval of publications between which the backlog will not be cleared
48
47
  # @param [Integer] max_backlog_size the largest permitted size (number of messages) for per-channel backlogs; beyond this capacity, old messages will be dropped.
49
48
  def initialize(redis_config = {}, max_backlog_size = 1000)
50
49
  @redis_config = redis_config.dup
50
+ @clear_every = redis_config.delete(:clear_every) || 1
51
51
  @logger = @redis_config[:logger]
52
52
  unless @redis_config[:enable_redis_logger]
53
53
  @redis_config[:logger] = nil
@@ -58,6 +58,8 @@ module MessageBus
58
58
  @in_memory_backlog = []
59
59
  @lock = Mutex.new
60
60
  @flush_backlog_thread = nil
61
+ @pub_redis = nil
62
+ @subscribed = false
61
63
  # after 7 days inactive backlogs will be removed
62
64
  @max_backlog_age = 604800
63
65
  end
@@ -98,6 +100,7 @@ module MessageBus
98
100
  local max_backlog_size = tonumber(ARGV[3])
99
101
  local max_global_backlog_size = tonumber(ARGV[4])
100
102
  local channel = ARGV[5]
103
+ local clear_every = ARGV[6]
101
104
 
102
105
  local global_id_key = KEYS[1]
103
106
  local backlog_id_key = KEYS[2]
@@ -118,11 +121,11 @@ module MessageBus
118
121
 
119
122
  redis.call("EXPIRE", backlog_id_key, max_backlog_age)
120
123
 
121
- if backlog_id > max_backlog_size then
124
+ if backlog_id > max_backlog_size and backlog_id % clear_every == 0 then
122
125
  redis.call("ZREMRANGEBYSCORE", backlog_key, 1, backlog_id - max_backlog_size)
123
126
  end
124
127
 
125
- if global_id > max_global_backlog_size then
128
+ if global_id > max_global_backlog_size and global_id % clear_every == 0 then
126
129
  redis.call("ZREMRANGEBYSCORE", global_backlog_key, 1, global_id - max_global_backlog_size)
127
130
  end
128
131
 
@@ -153,7 +156,8 @@ LUA
153
156
  max_backlog_age,
154
157
  max_backlog_size,
155
158
  max_global_backlog_size,
156
- channel
159
+ channel,
160
+ clear_every
157
161
  ],
158
162
  keys: [
159
163
  global_id_key,
@@ -192,6 +196,13 @@ LUA
192
196
  pub_redis.get(backlog_id_key).to_i
193
197
  end
194
198
 
199
+ # (see Base#last_ids)
200
+ def last_ids(*channels)
201
+ return [] if channels.size == 0
202
+ backlog_id_keys = channels.map { |c| backlog_id_key(c) }
203
+ pub_redis.mget(*backlog_id_keys).map(&:to_i)
204
+ end
205
+
195
206
  # (see Base#backlog)
196
207
  def backlog(channel, last_id = 0)
197
208
  redis = pub_redis
@@ -259,6 +270,7 @@ LUA
259
270
  new_redis.publish(redis_channel_name, UNSUB_MESSAGE)
260
271
  ensure
261
272
  new_redis&.disconnect!
273
+ @subscribed = false
262
274
  end
263
275
  end
264
276
 
@@ -301,6 +313,7 @@ LUA
301
313
 
302
314
  on.message do |_c, m|
303
315
  if m == UNSUB_MESSAGE
316
+ @subscribed = false
304
317
  global_redis.unsubscribe
305
318
  return
306
319
  end
@@ -178,31 +178,32 @@ class MessageBus::Client
178
178
  r = []
179
179
  new_message_ids = nil
180
180
 
181
- @subscriptions.each do |k, v|
182
- id = v.to_i
181
+ last_bus_ids = @bus.last_ids(*@subscriptions.keys, site_id: site_id)
183
182
 
184
- if id < -1
185
- last_id = @bus.last_id(k, site_id)
186
- id = last_id + id + 1
187
- id = 0 if id < 0
183
+ @subscriptions.each do |k, v|
184
+ last_client_id = v.to_i
185
+ last_bus_id = last_bus_ids[k]
186
+
187
+ if last_client_id < -1 # Client requesting backlog relative to bus position
188
+ last_client_id = last_bus_id + last_client_id + 1
189
+ last_client_id = 0 if last_client_id < 0
190
+ elsif last_client_id == -1 # Client not requesting backlog
191
+ next
192
+ elsif last_client_id == last_bus_id # Client already up-to-date
193
+ next
194
+ elsif last_client_id > last_bus_id # Client ahead of the bus
195
+ @subscriptions[k] = -1
196
+ next
188
197
  end
189
198
 
190
- next if id < 0
191
-
192
- messages = @bus.backlog(k, id, site_id)
199
+ messages = @bus.backlog(k, last_client_id, site_id)
193
200
 
194
- if messages.length == 0
195
- if id > @bus.last_id(k, site_id)
196
- @subscriptions[k] = -1
197
- end
198
- else
199
- messages.each do |msg|
200
- if allowed?(msg)
201
- r << msg
202
- else
203
- new_message_ids ||= {}
204
- new_message_ids[k] = msg.message_id
205
- end
201
+ messages.each do |msg|
202
+ if allowed?(msg)
203
+ r << msg
204
+ else
205
+ new_message_ids ||= {}
206
+ new_message_ids[k] = msg.message_id
206
207
  end
207
208
  end
208
209
  end
@@ -212,7 +213,7 @@ class MessageBus::Client
212
213
  @subscriptions.each do |k, v|
213
214
  if v.to_i == -1 || (new_message_ids && new_message_ids[k])
214
215
  status_message ||= {}
215
- @subscriptions[k] = status_message[k] = @bus.last_id(k, site_id)
216
+ @subscriptions[k] = status_message[k] = last_bus_ids[k]
216
217
  end
217
218
  end
218
219
 
@@ -41,7 +41,6 @@ class MessageBus::Rack::Middleware
41
41
  @started_listener = false
42
42
  @base_route = "#{@bus.base_route}message-bus/"
43
43
  @base_route_length = @base_route.length
44
- @diagnostics_route = "#{@base_route}_diagnostics"
45
44
  @broadcast_route = "#{@base_route}broadcast"
46
45
  start_listener unless @bus.off?
47
46
  end
@@ -79,11 +78,6 @@ class MessageBus::Rack::Middleware
79
78
  return [200, { "Content-Type" => "text/html" }, ["sent"]]
80
79
  end
81
80
 
82
- if env['PATH_INFO'].start_with? @diagnostics_route
83
- diags = MessageBus::Rack::Diagnostics.new(@app, message_bus: @bus)
84
- return diags.call(env)
85
- end
86
-
87
81
  client_id = env['PATH_INFO'][@base_route_length..-1].split("/")[0]
88
82
  return [404, {}, ["not found"]] unless client_id
89
83
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MessageBus
4
- VERSION = "3.3.8"
4
+ VERSION = "4.2.0"
5
5
  end
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"
@@ -47,21 +45,6 @@ module MessageBus::Implementation
47
45
  @subscriber_thread = nil
48
46
  end
49
47
 
50
- # @param [Boolean] val whether or not to cache static assets for the diagnostics pages
51
- # @return [void]
52
- def cache_assets=(val)
53
- configure(cache_assets: val)
54
- end
55
-
56
- # @return [Boolean] whether or not to cache static assets for the diagnostics pages
57
- def cache_assets
58
- if defined? @config[:cache_assets]
59
- @config[:cache_assets]
60
- else
61
- true
62
- end
63
- end
64
-
65
48
  # @param [Logger] logger a logger object to be used by the bus
66
49
  # @return [void]
67
50
  def logger=(logger)
@@ -297,15 +280,20 @@ module MessageBus::Implementation
297
280
  @config[:transport_codec] ||= MessageBus::Codec::Json.new
298
281
  end
299
282
 
300
- # @param [MessageBus::Backend::Base] pub_sub a configured backend
283
+ # @param [MessageBus::Backend::Base] backend_instance A configured backend
301
284
  # @return [void]
285
+ def backend_instance=(backend_instance)
286
+ configure(backend_instance: backend_instance)
287
+ end
288
+
302
289
  def reliable_pub_sub=(pub_sub)
303
- configure(reliable_pub_sub: pub_sub)
290
+ logger.warn "MessageBus.reliable_pub_sub= is deprecated, use MessageBus.backend_instance= instead."
291
+ self.backend_instance = pub_sub
304
292
  end
305
293
 
306
294
  # @return [MessageBus::Backend::Base] the configured backend. If not
307
295
  # explicitly set, will be loaded based on the configuration provided.
308
- def reliable_pub_sub
296
+ def backend_instance
309
297
  @mutex.synchronize do
310
298
  return nil if @destroyed
311
299
 
@@ -313,7 +301,7 @@ module MessageBus::Implementation
313
301
  # passed to backend.
314
302
  logger
315
303
 
316
- @config[:reliable_pub_sub] ||= begin
304
+ @config[:backend_instance] ||= begin
317
305
  @config[:backend_options] ||= {}
318
306
  require "message_bus/backends/#{backend}"
319
307
  MessageBus::BACKENDS[backend].new @config
@@ -321,17 +309,16 @@ module MessageBus::Implementation
321
309
  end
322
310
  end
323
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
+
324
317
  # @return [Symbol] the name of the backend implementation configured
325
318
  def backend
326
319
  @config[:backend] || :redis
327
320
  end
328
321
 
329
- # Enables diagnostics tracking
330
- # @return [void]
331
- def enable_diagnostics
332
- MessageBus::Diagnostics.enable(self)
333
- end
334
-
335
322
  # Publishes a message to a channel
336
323
  #
337
324
  # @param [String] channel the name of the channel to which the message should be published
@@ -398,7 +385,7 @@ module MessageBus::Implementation
398
385
  end
399
386
 
400
387
  encoded_channel_name = encode_channel_name(channel, site_id)
401
- reliable_pub_sub.publish(encoded_channel_name, encoded_data, channel_opts)
388
+ backend_instance.publish(encoded_channel_name, encoded_data, channel_opts)
402
389
  end
403
390
 
404
391
  # Subscribe to messages. Each message will be delivered by yielding to the
@@ -414,9 +401,9 @@ module MessageBus::Implementation
414
401
  # @return [void]
415
402
  def blocking_subscribe(channel = nil, &blk)
416
403
  if channel
417
- reliable_pub_sub.subscribe(encode_channel_name(channel), &blk)
404
+ backend_instance.subscribe(encode_channel_name(channel), &blk)
418
405
  else
419
- reliable_pub_sub.global_subscribe(&blk)
406
+ backend_instance.global_subscribe(&blk)
420
407
  end
421
408
  end
422
409
 
@@ -495,9 +482,9 @@ module MessageBus::Implementation
495
482
  def backlog(channel = nil, last_id = nil, site_id = nil)
496
483
  old =
497
484
  if channel
498
- reliable_pub_sub.backlog(encode_channel_name(channel, site_id), last_id)
485
+ backend_instance.backlog(encode_channel_name(channel, site_id), last_id)
499
486
  else
500
- reliable_pub_sub.global_backlog(last_id)
487
+ backend_instance.global_backlog(last_id)
501
488
  end
502
489
 
503
490
  old.each do |m|
@@ -513,7 +500,19 @@ module MessageBus::Implementation
513
500
  #
514
501
  # @return [Integer] the channel-specific ID of the last message published to the given channel
515
502
  def last_id(channel, site_id = nil)
516
- reliable_pub_sub.last_id(encode_channel_name(channel, site_id))
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
517
516
  end
518
517
 
519
518
  # Get the last message published on a channel
@@ -536,8 +535,8 @@ module MessageBus::Implementation
536
535
  def destroy
537
536
  return if @destroyed
538
537
 
539
- reliable_pub_sub.global_unsubscribe
540
- reliable_pub_sub.destroy
538
+ backend_instance.global_unsubscribe
539
+ backend_instance.destroy
541
540
 
542
541
  @mutex.synchronize do
543
542
  return if @destroyed
@@ -555,7 +554,7 @@ module MessageBus::Implementation
555
554
  # scheduled tasks.
556
555
  # @return [void]
557
556
  def after_fork
558
- reliable_pub_sub.after_fork
557
+ backend_instance.after_fork
559
558
  ensure_subscriber_thread
560
559
  # will ensure timer is running
561
560
  timer.queue {}
@@ -564,12 +563,12 @@ module MessageBus::Implementation
564
563
  # @return [Boolean] whether or not the server is actively listening for
565
564
  # publications on the bus
566
565
  def listening?
567
- @subscriber_thread && @subscriber_thread.alive?
566
+ @subscriber_thread&.alive?
568
567
  end
569
568
 
570
569
  # (see MessageBus::Backend::Base#reset!)
571
570
  def reset!
572
- reliable_pub_sub.reset! if reliable_pub_sub
571
+ backend_instance.reset! if backend_instance
573
572
  end
574
573
 
575
574
  # @return [MessageBus::TimerThread] the timer thread used for triggering
@@ -697,12 +696,6 @@ module MessageBus::Implementation
697
696
  @subscriptions[site_id][channel] << blk
698
697
  ensure_subscriber_thread
699
698
 
700
- attempts = 100
701
- while attempts > 0 && !reliable_pub_sub.subscribed
702
- sleep 0.001
703
- attempts -= 1
704
- end
705
-
706
699
  raise MessageBus::BusDestroyed if @destroyed
707
700
 
708
701
  blk
@@ -720,10 +713,17 @@ module MessageBus::Implementation
720
713
 
721
714
  def ensure_subscriber_thread
722
715
  @mutex.synchronize do
723
- return if (@subscriber_thread && @subscriber_thread.alive?) || @destroyed
716
+ return if @destroyed
717
+ next if @subscriber_thread&.alive?
724
718
 
725
719
  @subscriber_thread = new_subscriber_thread
726
720
  end
721
+
722
+ attempts = 100
723
+ while attempts > 0 && !backend_instance.subscribed
724
+ sleep 0.001
725
+ attempts -= 1
726
+ end
727
727
  end
728
728
 
729
729
  MIN_KEEPALIVE = 20
@@ -744,34 +744,11 @@ module MessageBus::Implementation
744
744
  if !@destroyed && thread.alive? && keepalive_interval > MIN_KEEPALIVE
745
745
 
746
746
  publish("/__mb_keepalive__/", Process.pid, user_ids: [-1])
747
- # going for x3 keepalives missed for a restart, need to ensure this only very rarely happens
748
- # note: after_fork will sort out a bad @last_message date, but thread will be dead anyway
749
747
  if (Time.now - (@last_message || Time.now)) > keepalive_interval * 3
750
- logger.warn "Global messages on #{Process.pid} timed out, restarting process"
751
- # No other clean way to remove this thread, its listening on a socket
752
- # no data is arriving
753
- #
754
- # In production we see this kind of situation ... sometimes ... when there is
755
- # a VRRP failover, or weird networking condition
756
- pid = Process.pid
757
-
758
- # do the best we can to terminate self cleanly
759
- fork do
760
- Process.kill('TERM', pid)
761
- sleep 10
762
- begin
763
- Process.kill('KILL', pid)
764
- rescue Errno::ESRCH
765
- logger.warn "#{Process.pid} successfully terminated by `TERM` signal."
766
- end
767
- end
768
-
769
- sleep 10
770
- Process.kill('KILL', pid)
771
-
772
- else
773
- 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"
774
749
  end
750
+
751
+ timer.queue(keepalive_interval, &blk) if keepalive_interval > MIN_KEEPALIVE
775
752
  end
776
753
  end
777
754
 
@@ -783,7 +760,7 @@ module MessageBus::Implementation
783
760
  def global_subscribe_thread
784
761
  # pretend we just got a message
785
762
  @last_message = Time.now
786
- reliable_pub_sub.global_subscribe do |msg|
763
+ backend_instance.global_subscribe do |msg|
787
764
  begin
788
765
  @last_message = Time.now
789
766
  decode_message!(msg)
data/message_bus.gemspec CHANGED
@@ -11,8 +11,6 @@ Gem::Specification.new do |gem|
11
11
  gem.license = "MIT"
12
12
  gem.files = `git ls-files`.split($\) +
13
13
  ["vendor/assets/javascripts/message-bus.js", "vendor/assets/javascripts/message-bus-ajax.js"]
14
- gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
15
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
14
  gem.name = "message_bus"
17
15
  gem.require_paths = ["lib"]
18
16
  gem.version = MessageBus::VERSION