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/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
|
-
|
10
|
+
Bundler.require(:default, :test)
|
10
11
|
|
11
|
-
|
12
|
+
RuboCop::RakeTask.new
|
12
13
|
YARD::Rake::YardocTask.new
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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:
|
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'] =
|
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/
|
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
|
@@ -84,6 +84,11 @@ module MessageBus
|
|
84
84
|
raise ConcreteClassMustImplementError
|
85
85
|
end
|
86
86
|
|
87
|
+
# Closes all open connections to the storage.
|
88
|
+
def destroy
|
89
|
+
raise ConcreteClassMustImplementError
|
90
|
+
end
|
91
|
+
|
87
92
|
# Deletes all backlogs and their data. Does not delete non-backlog data that message_bus may persist, depending on the concrete backend implementation. Use with extreme caution.
|
88
93
|
# @abstract
|
89
94
|
def expire_all_backlogs!
|
@@ -113,6 +118,15 @@ module MessageBus
|
|
113
118
|
raise ConcreteClassMustImplementError
|
114
119
|
end
|
115
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
|
+
|
116
130
|
# Get messages from a channel backlog
|
117
131
|
#
|
118
132
|
# @param [String] channel the name of the channel in question
|
@@ -212,6 +212,12 @@ module MessageBus
|
|
212
212
|
client.reset!
|
213
213
|
end
|
214
214
|
|
215
|
+
# No-op; this backend doesn't maintain any storage connections.
|
216
|
+
# (see Base#destroy)
|
217
|
+
def destroy
|
218
|
+
nil
|
219
|
+
end
|
220
|
+
|
215
221
|
# (see Base#expire_all_backlogs!)
|
216
222
|
def expire_all_backlogs!
|
217
223
|
client.expire_all_backlogs!
|
@@ -238,6 +244,13 @@ module MessageBus
|
|
238
244
|
client.max_id(channel)
|
239
245
|
end
|
240
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
|
+
|
241
254
|
# (see Base#backlog)
|
242
255
|
def backlog(channel, last_id = 0)
|
243
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
|
@@ -86,10 +87,12 @@ module MessageBus
|
|
86
87
|
hold { |conn| exec_prepared(conn, 'get_message', [channel, id]) { |r| r.getvalue(0, 0) } }
|
87
88
|
end
|
88
89
|
|
89
|
-
def
|
90
|
+
def after_fork
|
90
91
|
sync do
|
91
|
-
@
|
92
|
+
@pid = Process.pid
|
93
|
+
INHERITED_CONNECTIONS.concat(@available)
|
92
94
|
@available.clear
|
95
|
+
@listening_on.clear
|
93
96
|
end
|
94
97
|
end
|
95
98
|
|
@@ -101,6 +104,13 @@ module MessageBus
|
|
101
104
|
end
|
102
105
|
end
|
103
106
|
|
107
|
+
def destroy
|
108
|
+
sync do
|
109
|
+
@available.each(&:close)
|
110
|
+
@available.clear
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
104
114
|
# use with extreme care, will nuke all of the data
|
105
115
|
def expire_all_backlogs!
|
106
116
|
reset!
|
@@ -122,6 +132,21 @@ module MessageBus
|
|
122
132
|
end
|
123
133
|
end
|
124
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
|
+
|
125
150
|
def publish(channel, data)
|
126
151
|
hold { |conn| exec_prepared(conn, 'publish', [channel, data]) }
|
127
152
|
end
|
@@ -165,20 +190,23 @@ module MessageBus
|
|
165
190
|
end
|
166
191
|
|
167
192
|
def create_table(conn)
|
168
|
-
|
169
|
-
|
170
|
-
|
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
|
+
|
171
203
|
nil
|
172
204
|
end
|
173
205
|
|
174
206
|
def hold
|
175
207
|
current_pid = Process.pid
|
176
208
|
if current_pid != @pid
|
177
|
-
|
178
|
-
sync do
|
179
|
-
INHERITED_CONNECTIONS.concat(@available)
|
180
|
-
@available.clear
|
181
|
-
end
|
209
|
+
after_fork
|
182
210
|
end
|
183
211
|
|
184
212
|
if conn = sync { @allocated[Thread.current] }
|
@@ -208,11 +236,7 @@ module MessageBus
|
|
208
236
|
def new_pg_connection
|
209
237
|
conn = raw_pg_connection
|
210
238
|
|
211
|
-
|
212
|
-
conn.exec("SELECT 'message_bus'::regclass")
|
213
|
-
rescue PG::UndefinedTable
|
214
|
-
create_table(conn)
|
215
|
-
end
|
239
|
+
create_table(conn)
|
216
240
|
|
217
241
|
conn.exec 'PREPARE insert_message AS INSERT INTO message_bus (channel, value) VALUES ($1, $2) RETURNING id'
|
218
242
|
conn.exec 'PREPARE clear_global_backlog AS DELETE FROM message_bus WHERE (id <= $1)'
|
@@ -222,6 +246,7 @@ module MessageBus
|
|
222
246
|
conn.exec "PREPARE expire AS DELETE FROM message_bus WHERE added_at < CURRENT_TIMESTAMP - ($1::text || ' seconds')::interval"
|
223
247
|
conn.exec 'PREPARE get_message AS SELECT value FROM message_bus WHERE ((channel = $1) AND (id = $2))'
|
224
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'
|
225
250
|
conn.exec 'PREPARE max_id AS SELECT max(id) FROM message_bus'
|
226
251
|
conn.exec 'PREPARE publish AS SELECT pg_notify($1, $2)'
|
227
252
|
|
@@ -253,12 +278,14 @@ module MessageBus
|
|
253
278
|
# after 7 days inactive backlogs will be removed
|
254
279
|
@max_backlog_age = 604800
|
255
280
|
@clear_every = config[:clear_every] || 1
|
281
|
+
@mutex = Mutex.new
|
282
|
+
@client = nil
|
256
283
|
end
|
257
284
|
|
258
285
|
# Reconnects to Postgres; used after a process fork, typically triggered by a forking webserver
|
259
286
|
# @see Base#after_fork
|
260
287
|
def after_fork
|
261
|
-
client.
|
288
|
+
client.after_fork
|
262
289
|
end
|
263
290
|
|
264
291
|
# (see Base#reset!)
|
@@ -266,6 +293,11 @@ module MessageBus
|
|
266
293
|
client.reset!
|
267
294
|
end
|
268
295
|
|
296
|
+
# (see Base#destroy)
|
297
|
+
def destroy
|
298
|
+
client.destroy
|
299
|
+
end
|
300
|
+
|
269
301
|
# (see Base#expire_all_backlogs!)
|
270
302
|
def expire_all_backlogs!
|
271
303
|
client.expire_all_backlogs!
|
@@ -297,7 +329,12 @@ module MessageBus
|
|
297
329
|
client.max_id(channel)
|
298
330
|
end
|
299
331
|
|
300
|
-
# (see Base#
|
332
|
+
# (see Base#last_ids)
|
333
|
+
def last_ids(*channels)
|
334
|
+
client.max_ids(*channels)
|
335
|
+
end
|
336
|
+
|
337
|
+
# (see Base#backlog)
|
301
338
|
def backlog(channel, last_id = 0)
|
302
339
|
items = client.backlog channel, last_id.to_i
|
303
340
|
|
@@ -401,11 +438,7 @@ module MessageBus
|
|
401
438
|
private
|
402
439
|
|
403
440
|
def client
|
404
|
-
@client ||=
|
405
|
-
end
|
406
|
-
|
407
|
-
def new_connection
|
408
|
-
Client.new(@config)
|
441
|
+
@client || @mutex.synchronize { @client ||= Client.new(@config) }
|
409
442
|
end
|
410
443
|
|
411
444
|
def postgresql_channel_name
|
@@ -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
|
@@ -65,7 +67,7 @@ module MessageBus
|
|
65
67
|
# Reconnects to Redis; used after a process fork, typically triggered by a forking webserver
|
66
68
|
# @see Base#after_fork
|
67
69
|
def after_fork
|
68
|
-
pub_redis
|
70
|
+
@pub_redis&.disconnect!
|
69
71
|
end
|
70
72
|
|
71
73
|
# (see Base#reset!)
|
@@ -75,6 +77,11 @@ module MessageBus
|
|
75
77
|
end
|
76
78
|
end
|
77
79
|
|
80
|
+
# (see Base#destroy)
|
81
|
+
def destroy
|
82
|
+
@pub_redis&.disconnect!
|
83
|
+
end
|
84
|
+
|
78
85
|
# Deletes all backlogs and their data. Does not delete ID pointers, so new publications will get IDs that continue from the last publication before the expiry. Use with extreme caution.
|
79
86
|
# @see Base#expire_all_backlogs!
|
80
87
|
def expire_all_backlogs!
|
@@ -187,6 +194,13 @@ LUA
|
|
187
194
|
pub_redis.get(backlog_id_key).to_i
|
188
195
|
end
|
189
196
|
|
197
|
+
# (see Base#last_ids)
|
198
|
+
def last_ids(*channels)
|
199
|
+
return [] if channels.size == 0
|
200
|
+
backlog_id_keys = channels.map { |c| backlog_id_key(c) }
|
201
|
+
pub_redis.mget(*backlog_id_keys).map(&:to_i)
|
202
|
+
end
|
203
|
+
|
190
204
|
# (see Base#backlog)
|
191
205
|
def backlog(channel, last_id = 0)
|
192
206
|
redis = pub_redis
|
@@ -254,6 +268,7 @@ LUA
|
|
254
268
|
new_redis.publish(redis_channel_name, UNSUB_MESSAGE)
|
255
269
|
ensure
|
256
270
|
new_redis&.disconnect!
|
271
|
+
@subscribed = false
|
257
272
|
end
|
258
273
|
end
|
259
274
|
|
@@ -296,6 +311,7 @@ LUA
|
|
296
311
|
|
297
312
|
on.message do |_c, m|
|
298
313
|
if m == UNSUB_MESSAGE
|
314
|
+
@subscribed = false
|
299
315
|
global_redis.unsubscribe
|
300
316
|
return
|
301
317
|
end
|
data/lib/message_bus/client.rb
CHANGED
@@ -46,6 +46,9 @@ class MessageBus::Client
|
|
46
46
|
@bus = opts[:message_bus] || MessageBus
|
47
47
|
@subscriptions = {}
|
48
48
|
@chunks_sent = 0
|
49
|
+
@async_response = nil
|
50
|
+
@io = nil
|
51
|
+
@wrote_headers = false
|
49
52
|
end
|
50
53
|
|
51
54
|
# @yield executed with a lock on the Client instance
|
@@ -175,31 +178,32 @@ class MessageBus::Client
|
|
175
178
|
r = []
|
176
179
|
new_message_ids = nil
|
177
180
|
|
178
|
-
@subscriptions.
|
179
|
-
id = v.to_i
|
181
|
+
last_bus_ids = @bus.last_ids(*@subscriptions.keys, site_id: site_id)
|
180
182
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
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
|
185
197
|
end
|
186
198
|
|
187
|
-
|
199
|
+
messages = @bus.backlog(k, last_client_id, site_id)
|
188
200
|
|
189
|
-
messages
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
else
|
196
|
-
messages.each do |msg|
|
197
|
-
if allowed?(msg)
|
198
|
-
r << msg
|
199
|
-
else
|
200
|
-
new_message_ids ||= {}
|
201
|
-
new_message_ids[k] = msg.message_id
|
202
|
-
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
|
203
207
|
end
|
204
208
|
end
|
205
209
|
end
|
@@ -209,7 +213,7 @@ class MessageBus::Client
|
|
209
213
|
@subscriptions.each do |k, v|
|
210
214
|
if v.to_i == -1 || (new_message_ids && new_message_ids[k])
|
211
215
|
status_message ||= {}
|
212
|
-
@subscriptions[k] = status_message[k] =
|
216
|
+
@subscriptions[k] = status_message[k] = last_bus_ids[k]
|
213
217
|
end
|
214
218
|
end
|
215
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
|
|
data/lib/message_bus/version.rb
CHANGED