message_bus 3.3.4 → 3.3.8
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 +21 -0
- data/.github/workflows/ci.yml +99 -0
- data/.gitignore +2 -0
- data/.prettierrc +1 -0
- data/.rubocop.yml +3 -1
- data/CHANGELOG +30 -8
- data/DEV.md +7 -0
- data/Gemfile +0 -25
- data/LICENSE +1 -1
- data/README.md +34 -15
- data/Rakefile +13 -8
- data/assets/message-bus-ajax.js +4 -10
- data/assets/message-bus.js +69 -76
- data/bench/codecs/all_codecs.rb +39 -0
- data/bench/codecs/marshal.rb +11 -0
- data/bench/codecs/packed_string.rb +67 -0
- data/bench/codecs/string_hack.rb +47 -0
- data/bench/codecs_large_user_list.rb +29 -0
- data/bench/codecs_standard_message.rb +29 -0
- data/examples/bench/bench.lua +2 -2
- data/lib/message_bus/backends/base.rb +8 -5
- data/lib/message_bus/backends/memory.rb +6 -2
- data/lib/message_bus/backends/postgres.rb +27 -18
- data/lib/message_bus/backends/redis.rb +9 -6
- data/lib/message_bus/client.rb +6 -7
- data/lib/message_bus/codec/base.rb +18 -0
- data/lib/message_bus/codec/json.rb +15 -0
- data/lib/message_bus/codec/oj.rb +21 -0
- data/lib/message_bus/connection_manager.rb +1 -1
- data/lib/message_bus/distributed_cache.rb +3 -1
- data/lib/message_bus/http_client.rb +2 -2
- data/lib/message_bus/rack/diagnostics.rb +30 -8
- data/lib/message_bus/rack/middleware.rb +22 -16
- data/lib/message_bus/rack/thin_ext.rb +2 -1
- data/lib/message_bus/version.rb +1 -1
- data/lib/message_bus.rb +42 -22
- data/message_bus.gemspec +21 -3
- data/package-lock.json +3744 -0
- data/package.json +15 -8
- data/spec/assets/SpecHelper.js +6 -5
- data/spec/assets/message-bus.spec.js +9 -6
- data/spec/helpers.rb +23 -7
- data/spec/integration/http_client_spec.rb +1 -1
- data/spec/lib/fake_async_middleware.rb +1 -0
- data/spec/lib/message_bus/backend_spec.rb +13 -44
- data/spec/lib/message_bus/client_spec.rb +7 -6
- data/spec/lib/message_bus/connection_manager_spec.rb +4 -0
- data/spec/lib/message_bus/distributed_cache_spec.rb +5 -7
- data/spec/lib/message_bus/multi_process_spec.rb +19 -9
- data/spec/lib/message_bus/rack/middleware_spec.rb +18 -6
- data/spec/lib/message_bus_spec.rb +13 -8
- data/spec/spec_helper.rb +8 -9
- data/spec/support/jasmine-browser.json +16 -0
- data/vendor/assets/javascripts/message-bus-ajax.js +4 -10
- data/vendor/assets/javascripts/message-bus.js +69 -76
- metadata +231 -11
- data/.travis.yml +0 -17
- data/lib/message_bus/em_ext.rb +0 -6
- data/spec/assets/support/jasmine.yml +0 -126
- data/spec/assets/support/jasmine_helper.rb +0 -11
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "message_bus/backends/base"
|
4
|
-
|
5
3
|
module MessageBus
|
6
4
|
module Backends
|
7
5
|
# The memory backend stores published messages in a simple array per
|
@@ -214,6 +212,12 @@ module MessageBus
|
|
214
212
|
client.reset!
|
215
213
|
end
|
216
214
|
|
215
|
+
# No-op; this backend doesn't maintain any storage connections.
|
216
|
+
# (see Base#destroy)
|
217
|
+
def destroy
|
218
|
+
nil
|
219
|
+
end
|
220
|
+
|
217
221
|
# (see Base#expire_all_backlogs!)
|
218
222
|
def expire_all_backlogs!
|
219
223
|
client.expire_all_backlogs!
|
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'pg'
|
4
4
|
|
5
|
-
require "message_bus/backends/base"
|
6
|
-
|
7
5
|
module MessageBus
|
8
6
|
module Backends
|
9
7
|
# The Postgres backend stores published messages in a single Postgres table
|
@@ -46,6 +44,7 @@ module MessageBus
|
|
46
44
|
@listening_on = {}
|
47
45
|
@available = []
|
48
46
|
@allocated = {}
|
47
|
+
@subscribe_connection = nil
|
49
48
|
@mutex = Mutex.new
|
50
49
|
@pid = Process.pid
|
51
50
|
end
|
@@ -87,10 +86,12 @@ module MessageBus
|
|
87
86
|
hold { |conn| exec_prepared(conn, 'get_message', [channel, id]) { |r| r.getvalue(0, 0) } }
|
88
87
|
end
|
89
88
|
|
90
|
-
def
|
89
|
+
def after_fork
|
91
90
|
sync do
|
92
|
-
@
|
91
|
+
@pid = Process.pid
|
92
|
+
INHERITED_CONNECTIONS.concat(@available)
|
93
93
|
@available.clear
|
94
|
+
@listening_on.clear
|
94
95
|
end
|
95
96
|
end
|
96
97
|
|
@@ -102,6 +103,13 @@ module MessageBus
|
|
102
103
|
end
|
103
104
|
end
|
104
105
|
|
106
|
+
def destroy
|
107
|
+
sync do
|
108
|
+
@available.each(&:close)
|
109
|
+
@available.clear
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
105
113
|
# use with extreme care, will nuke all of the data
|
106
114
|
def expire_all_backlogs!
|
107
115
|
reset!
|
@@ -133,7 +141,7 @@ module MessageBus
|
|
133
141
|
listener = Listener.new
|
134
142
|
yield listener
|
135
143
|
|
136
|
-
conn = raw_pg_connection
|
144
|
+
conn = @subscribe_connection = raw_pg_connection
|
137
145
|
conn.exec "LISTEN #{channel}"
|
138
146
|
listener.do_sub.call
|
139
147
|
while listening_on?(channel, obj)
|
@@ -147,6 +155,9 @@ module MessageBus
|
|
147
155
|
|
148
156
|
conn.exec "UNLISTEN #{channel}"
|
149
157
|
nil
|
158
|
+
ensure
|
159
|
+
@subscribe_connection&.close
|
160
|
+
@subscribe_connection = nil
|
150
161
|
end
|
151
162
|
|
152
163
|
def unsubscribe
|
@@ -172,11 +183,7 @@ module MessageBus
|
|
172
183
|
def hold
|
173
184
|
current_pid = Process.pid
|
174
185
|
if current_pid != @pid
|
175
|
-
|
176
|
-
sync do
|
177
|
-
INHERITED_CONNECTIONS.concat(@available)
|
178
|
-
@available.clear
|
179
|
-
end
|
186
|
+
after_fork
|
180
187
|
end
|
181
188
|
|
182
189
|
if conn = sync { @allocated[Thread.current] }
|
@@ -251,12 +258,13 @@ module MessageBus
|
|
251
258
|
# after 7 days inactive backlogs will be removed
|
252
259
|
@max_backlog_age = 604800
|
253
260
|
@clear_every = config[:clear_every] || 1
|
261
|
+
@mutex = Mutex.new
|
254
262
|
end
|
255
263
|
|
256
|
-
# Reconnects to Postgres; used after a process fork, typically
|
264
|
+
# Reconnects to Postgres; used after a process fork, typically triggered by a forking webserver
|
257
265
|
# @see Base#after_fork
|
258
266
|
def after_fork
|
259
|
-
client.
|
267
|
+
client.after_fork
|
260
268
|
end
|
261
269
|
|
262
270
|
# (see Base#reset!)
|
@@ -264,6 +272,11 @@ module MessageBus
|
|
264
272
|
client.reset!
|
265
273
|
end
|
266
274
|
|
275
|
+
# (see Base#destroy)
|
276
|
+
def destroy
|
277
|
+
client.destroy
|
278
|
+
end
|
279
|
+
|
267
280
|
# (see Base#expire_all_backlogs!)
|
268
281
|
def expire_all_backlogs!
|
269
282
|
client.expire_all_backlogs!
|
@@ -279,7 +292,7 @@ module MessageBus
|
|
279
292
|
msg = MessageBus::Message.new backlog_id, backlog_id, channel, data
|
280
293
|
payload = msg.encode
|
281
294
|
c.publish postgresql_channel_name, payload
|
282
|
-
if backlog_id % clear_every == 0
|
295
|
+
if backlog_id && backlog_id % clear_every == 0
|
283
296
|
max_backlog_size = (opts && opts[:max_backlog_size]) || self.max_backlog_size
|
284
297
|
max_backlog_age = (opts && opts[:max_backlog_age]) || self.max_backlog_age
|
285
298
|
c.clear_global_backlog(backlog_id, @max_global_backlog_size)
|
@@ -399,11 +412,7 @@ module MessageBus
|
|
399
412
|
private
|
400
413
|
|
401
414
|
def client
|
402
|
-
@client ||=
|
403
|
-
end
|
404
|
-
|
405
|
-
def new_connection
|
406
|
-
Client.new(@config)
|
415
|
+
@client || @mutex.synchronize { @client ||= Client.new(@config) }
|
407
416
|
end
|
408
417
|
|
409
418
|
def postgresql_channel_name
|
@@ -3,8 +3,6 @@
|
|
3
3
|
require 'redis'
|
4
4
|
require 'digest'
|
5
5
|
|
6
|
-
require "message_bus/backends/base"
|
7
|
-
|
8
6
|
module MessageBus
|
9
7
|
module Backends
|
10
8
|
# The Redis backend stores published messages in Redis sorted sets (using
|
@@ -64,10 +62,10 @@ module MessageBus
|
|
64
62
|
@max_backlog_age = 604800
|
65
63
|
end
|
66
64
|
|
67
|
-
# Reconnects to Redis; used after a process fork, typically
|
65
|
+
# Reconnects to Redis; used after a process fork, typically triggered by a forking webserver
|
68
66
|
# @see Base#after_fork
|
69
67
|
def after_fork
|
70
|
-
pub_redis
|
68
|
+
@pub_redis&.disconnect!
|
71
69
|
end
|
72
70
|
|
73
71
|
# (see Base#reset!)
|
@@ -77,6 +75,11 @@ module MessageBus
|
|
77
75
|
end
|
78
76
|
end
|
79
77
|
|
78
|
+
# (see Base#destroy)
|
79
|
+
def destroy
|
80
|
+
@pub_redis&.disconnect!
|
81
|
+
end
|
82
|
+
|
80
83
|
# 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.
|
81
84
|
# @see Base#expire_all_backlogs!
|
82
85
|
def expire_all_backlogs!
|
@@ -104,8 +107,8 @@ module MessageBus
|
|
104
107
|
|
105
108
|
local global_id = redis.call("INCR", global_id_key)
|
106
109
|
local backlog_id = redis.call("INCR", backlog_id_key)
|
107
|
-
local payload =
|
108
|
-
local global_backlog_message =
|
110
|
+
local payload = table.concat({ global_id, backlog_id, start_payload }, "|")
|
111
|
+
local global_backlog_message = table.concat({ backlog_id, channel }, "|")
|
109
112
|
|
110
113
|
redis.call("ZADD", backlog_key, backlog_id, payload)
|
111
114
|
redis.call("EXPIRE", backlog_key, max_backlog_age)
|
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
|
@@ -220,7 +223,7 @@ class MessageBus::Client
|
|
220
223
|
|
221
224
|
private
|
222
225
|
|
223
|
-
# heavily optimised to avoid all
|
226
|
+
# heavily optimised to avoid all unneeded allocations
|
224
227
|
NEWLINE = "\r\n".freeze
|
225
228
|
COLON_SPACE = ": ".freeze
|
226
229
|
HTTP_11 = "HTTP/1.1 200 OK\r\n".freeze
|
@@ -261,7 +264,7 @@ class MessageBus::Client
|
|
261
264
|
@wrote_headers = true
|
262
265
|
end
|
263
266
|
|
264
|
-
# chunked encoding may be "re-chunked" by proxies, so add a
|
267
|
+
# chunked encoding may be "re-chunked" by proxies, so add a separator
|
265
268
|
postfix = NEWLINE + "|" + NEWLINE
|
266
269
|
data = data.gsub(postfix, NEWLINE + "||" + NEWLINE)
|
267
270
|
chunk_length = data.bytesize + postfix.bytesize
|
@@ -275,11 +278,7 @@ class MessageBus::Client
|
|
275
278
|
@async_response << postfix
|
276
279
|
@async_response << NEWLINE
|
277
280
|
else
|
278
|
-
@io.write(chunk_length.to_s(16))
|
279
|
-
@io.write(NEWLINE)
|
280
|
-
@io.write(data)
|
281
|
-
@io.write(postfix)
|
282
|
-
@io.write(NEWLINE)
|
281
|
+
@io.write(chunk_length.to_s(16) << NEWLINE << data << postfix << NEWLINE)
|
283
282
|
end
|
284
283
|
end
|
285
284
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MessageBus
|
4
|
+
module Codec
|
5
|
+
class Base
|
6
|
+
def encode(hash)
|
7
|
+
raise ConcreteClassMustImplementError
|
8
|
+
end
|
9
|
+
|
10
|
+
def decode(payload)
|
11
|
+
raise ConcreteClassMustImplementError
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
autoload :Json, File.expand_path("json", __dir__)
|
16
|
+
autoload :Oj, File.expand_path("oj", __dir__)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'oj' unless defined? ::Oj
|
4
|
+
|
5
|
+
module MessageBus
|
6
|
+
module Codec
|
7
|
+
class Oj < Base
|
8
|
+
def initialize(options = { mode: :compat })
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def encode(hash)
|
13
|
+
::Oj.dump(hash, @options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def decode(payload)
|
17
|
+
::Oj.load(payload, @options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -22,6 +22,7 @@ module MessageBus
|
|
22
22
|
@lock = Mutex.new
|
23
23
|
@message_bus = message_bus || MessageBus
|
24
24
|
@publish_queue_in_memory = publish_queue_in_memory
|
25
|
+
@app_version = nil
|
25
26
|
end
|
26
27
|
|
27
28
|
def subscribers
|
@@ -45,7 +46,8 @@ module MessageBus
|
|
45
46
|
hash = current.hash(message.site_id || DEFAULT_SITE_ID)
|
46
47
|
|
47
48
|
case payload["op"]
|
48
|
-
|
49
|
+
# TODO: consider custom marshal support with a restricted set
|
50
|
+
when "set" then hash[payload["key"]] = payload["marshalled"] ? Marshal.load(Base64.decode64(payload["value"])) : payload["value"] # rubocop:disable Security/MarshalLoad
|
49
51
|
when "delete" then hash.delete(payload["key"])
|
50
52
|
when "clear" then hash.clear
|
51
53
|
end
|
@@ -146,8 +146,8 @@ module MessageBus
|
|
146
146
|
#
|
147
147
|
# A last_message_id may be provided.
|
148
148
|
# * -1 will subscribe to all new messages
|
149
|
-
# * -2 will
|
150
|
-
# * -3 will
|
149
|
+
# * -2 will receive last message + all new messages
|
150
|
+
# * -3 will receive last 2 message + all new messages
|
151
151
|
#
|
152
152
|
# @example Subscribing to a channel with `last_message_id`
|
153
153
|
# client.subscribe("/test", last_message_id: -2) do |payload|
|
@@ -13,6 +13,15 @@ class MessageBus::Rack::Diagnostics
|
|
13
13
|
@bus = config[:message_bus] || MessageBus
|
14
14
|
end
|
15
15
|
|
16
|
+
JS_ASSETS = %w{
|
17
|
+
jquery-1.8.2.js
|
18
|
+
react.js
|
19
|
+
react-dom.js
|
20
|
+
babel.min.js
|
21
|
+
message-bus.js
|
22
|
+
application.jsx
|
23
|
+
}
|
24
|
+
|
16
25
|
# Process an HTTP request from a subscriber client
|
17
26
|
# @param [Rack::Request::Env] env the request environment
|
18
27
|
def call(env)
|
@@ -39,9 +48,9 @@ class MessageBus::Rack::Diagnostics
|
|
39
48
|
end
|
40
49
|
|
41
50
|
asset = route.split('/assets/')[1]
|
42
|
-
|
51
|
+
|
52
|
+
if asset && JS_ASSETS.include?(asset)
|
43
53
|
content = asset_contents(asset)
|
44
|
-
split = asset.split('.')
|
45
54
|
return [200, { 'Content-Type' => 'application/javascript;charset=UTF-8' }, [content]]
|
46
55
|
end
|
47
56
|
|
@@ -75,6 +84,23 @@ class MessageBus::Rack::Diagnostics
|
|
75
84
|
File.expand_path("../../../../assets/#{asset}", __FILE__)
|
76
85
|
end
|
77
86
|
|
87
|
+
def script_tags
|
88
|
+
tags = []
|
89
|
+
|
90
|
+
JS_ASSETS.each do |asset|
|
91
|
+
type =
|
92
|
+
if asset.end_with?('.js')
|
93
|
+
'text/javascript'
|
94
|
+
elsif asset.end_with?('.jsx')
|
95
|
+
'text/jsx'
|
96
|
+
end
|
97
|
+
|
98
|
+
tags << js_asset(asset, type)
|
99
|
+
end
|
100
|
+
|
101
|
+
tags.join("\n")
|
102
|
+
end
|
103
|
+
|
78
104
|
def index
|
79
105
|
html = <<~HTML
|
80
106
|
<!DOCTYPE html>
|
@@ -83,12 +109,8 @@ class MessageBus::Rack::Diagnostics
|
|
83
109
|
</head>
|
84
110
|
<body>
|
85
111
|
<div id="app"></div>
|
86
|
-
|
87
|
-
#{
|
88
|
-
#{js_asset "react-dom.js"}
|
89
|
-
#{js_asset "babel.min.js"}
|
90
|
-
#{js_asset "message-bus.js"}
|
91
|
-
#{js_asset "application.jsx", "text/jsx"}
|
112
|
+
|
113
|
+
#{script_tags}
|
92
114
|
</body>
|
93
115
|
</html>
|
94
116
|
HTML
|
@@ -66,6 +66,12 @@ class MessageBus::Rack::Middleware
|
|
66
66
|
private
|
67
67
|
|
68
68
|
def handle_request(env)
|
69
|
+
# Prevent simple polling from clobbering the session
|
70
|
+
# See: https://github.com/discourse/message_bus/issues/257
|
71
|
+
if (rack_session_options = env[Rack::RACK_SESSION_OPTIONS])
|
72
|
+
rack_session_options[:skip] = true
|
73
|
+
end
|
74
|
+
|
69
75
|
# special debug/test route
|
70
76
|
if @bus.allow_broadcast? && env['PATH_INFO'] == @broadcast_route
|
71
77
|
parsed = Rack::Request.new(env)
|
@@ -81,6 +87,22 @@ class MessageBus::Rack::Middleware
|
|
81
87
|
client_id = env['PATH_INFO'][@base_route_length..-1].split("/")[0]
|
82
88
|
return [404, {}, ["not found"]] unless client_id
|
83
89
|
|
90
|
+
headers = {}
|
91
|
+
headers["Cache-Control"] = "must-revalidate, private, max-age=0"
|
92
|
+
headers["Content-Type"] = "application/json; charset=utf-8"
|
93
|
+
headers["Pragma"] = "no-cache"
|
94
|
+
headers["Expires"] = "0"
|
95
|
+
|
96
|
+
if @bus.extra_response_headers_lookup
|
97
|
+
@bus.extra_response_headers_lookup.call(env).each do |k, v|
|
98
|
+
headers[k] = v
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
if env["REQUEST_METHOD"] == "OPTIONS"
|
103
|
+
return [200, headers, ["OK"]]
|
104
|
+
end
|
105
|
+
|
84
106
|
user_id = @bus.user_id_lookup.call(env) if @bus.user_id_lookup
|
85
107
|
group_ids = @bus.group_ids_lookup.call(env) if @bus.group_ids_lookup
|
86
108
|
site_id = @bus.site_id_lookup.call(env) if @bus.site_id_lookup
|
@@ -111,22 +133,6 @@ class MessageBus::Rack::Middleware
|
|
111
133
|
end
|
112
134
|
end
|
113
135
|
|
114
|
-
headers = {}
|
115
|
-
headers["Cache-Control"] = "must-revalidate, private, max-age=0"
|
116
|
-
headers["Content-Type"] = "application/json; charset=utf-8"
|
117
|
-
headers["Pragma"] = "no-cache"
|
118
|
-
headers["Expires"] = "0"
|
119
|
-
|
120
|
-
if @bus.extra_response_headers_lookup
|
121
|
-
@bus.extra_response_headers_lookup.call(env).each do |k, v|
|
122
|
-
headers[k] = v
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
if env["REQUEST_METHOD"] == "OPTIONS"
|
127
|
-
return [200, headers, ["OK"]]
|
128
|
-
end
|
129
|
-
|
130
136
|
long_polling = @bus.long_polling_enabled? &&
|
131
137
|
env['QUERY_STRING'] !~ /dlp=t/ &&
|
132
138
|
@connection_manager.client_count < @bus.max_active_clients
|
@@ -9,6 +9,7 @@ module Thin
|
|
9
9
|
|
10
10
|
def initialize
|
11
11
|
@queue = []
|
12
|
+
@body_callback = nil
|
12
13
|
end
|
13
14
|
|
14
15
|
def call(body)
|
@@ -38,7 +39,7 @@ module Thin
|
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
41
|
-
# Response
|
42
|
+
# Response which body is sent asynchronously.
|
42
43
|
class AsyncResponse
|
43
44
|
include Rack::Response::Helpers
|
44
45
|
|
data/lib/message_bus/version.rb
CHANGED
data/lib/message_bus.rb
CHANGED
@@ -2,18 +2,22 @@
|
|
2
2
|
|
3
3
|
require "monitor"
|
4
4
|
require "set"
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
|
6
|
+
require_relative "message_bus/version"
|
7
|
+
require_relative "message_bus/message"
|
8
|
+
require_relative "message_bus/client"
|
9
|
+
require_relative "message_bus/connection_manager"
|
10
|
+
require_relative "message_bus/diagnostics"
|
11
|
+
require_relative "message_bus/rack/middleware"
|
12
|
+
require_relative "message_bus/rack/diagnostics"
|
13
|
+
require_relative "message_bus/timer_thread"
|
14
|
+
require_relative "message_bus/codec/base"
|
15
|
+
require_relative "message_bus/backends"
|
16
|
+
require_relative "message_bus/backends/base"
|
13
17
|
|
14
18
|
# we still need to take care of the logger
|
15
|
-
if defined?(::Rails)
|
16
|
-
|
19
|
+
if defined?(::Rails::Engine)
|
20
|
+
require_relative 'message_bus/rails/railtie'
|
17
21
|
end
|
18
22
|
|
19
23
|
# @see MessageBus::Implementation
|
@@ -37,6 +41,10 @@ module MessageBus::Implementation
|
|
37
41
|
def initialize
|
38
42
|
@config = {}
|
39
43
|
@mutex = Synchronizer.new
|
44
|
+
@off = false
|
45
|
+
@destroyed = false
|
46
|
+
@timer_thread = nil
|
47
|
+
@subscriber_thread = nil
|
40
48
|
end
|
41
49
|
|
42
50
|
# @param [Boolean] val whether or not to cache static assets for the diagnostics pages
|
@@ -96,14 +104,14 @@ module MessageBus::Implementation
|
|
96
104
|
configure(long_polling_enabled: val)
|
97
105
|
end
|
98
106
|
|
99
|
-
# @param [Integer] val The number of
|
107
|
+
# @param [Integer] val The number of simultaneous clients we can service;
|
100
108
|
# will revert to polling if we are out of slots
|
101
109
|
# @return [void]
|
102
110
|
def max_active_clients=(val)
|
103
111
|
configure(max_active_clients: val)
|
104
112
|
end
|
105
113
|
|
106
|
-
# @return [Integer] The number of
|
114
|
+
# @return [Integer] The number of simultaneous clients we can service;
|
107
115
|
# will revert to polling if we are out of slots. Defaults to 1000 if not
|
108
116
|
# explicitly set.
|
109
117
|
def max_active_clients
|
@@ -271,13 +279,24 @@ module MessageBus::Implementation
|
|
271
279
|
# set, defaults to false unless we're in Rails test or development mode.
|
272
280
|
def allow_broadcast?
|
273
281
|
@config[:allow_broadcast] ||=
|
274
|
-
if defined? ::Rails
|
282
|
+
if defined? ::Rails.env
|
275
283
|
::Rails.env.test? || ::Rails.env.development?
|
276
284
|
else
|
277
285
|
false
|
278
286
|
end
|
279
287
|
end
|
280
288
|
|
289
|
+
# @param [MessageBus::Codec::Base] codec used to encode and decode Message payloads
|
290
|
+
# @return [void]
|
291
|
+
def transport_codec=(codec)
|
292
|
+
configure(transport_codec: codec)
|
293
|
+
end
|
294
|
+
|
295
|
+
# @return [MessageBus::Codec::Base] codec used to encode and decode Message payloads
|
296
|
+
def transport_codec
|
297
|
+
@config[:transport_codec] ||= MessageBus::Codec::Json.new
|
298
|
+
end
|
299
|
+
|
281
300
|
# @param [MessageBus::Backend::Base] pub_sub a configured backend
|
282
301
|
# @return [void]
|
283
302
|
def reliable_pub_sub=(pub_sub)
|
@@ -323,7 +342,7 @@ module MessageBus::Implementation
|
|
323
342
|
# @option opts [Array<String,Integer>] :group_ids (`nil`) the group IDs to which the message should be available. If nil, available to all.
|
324
343
|
# @option opts [String] :site_id (`nil`) the site ID to scope the message to; used for hosting multiple
|
325
344
|
# applications or instances of an application against a single message_bus
|
326
|
-
# @option opts [nil,Integer] :max_backlog_age the longest amount of time a message may live in a backlog before
|
345
|
+
# @option opts [nil,Integer] :max_backlog_age the longest amount of time a message may live in a backlog before being removed, in seconds
|
327
346
|
# @option opts [nil,Integer] :max_backlog_size the largest permitted size (number of messages) for the channel backlog; beyond this capacity, old messages will be dropped
|
328
347
|
#
|
329
348
|
# @return [Integer] the channel-specific ID the message was given
|
@@ -358,12 +377,12 @@ module MessageBus::Implementation
|
|
358
377
|
raise ::MessageBus::InvalidMessageTarget
|
359
378
|
end
|
360
379
|
|
361
|
-
encoded_data =
|
362
|
-
data
|
363
|
-
user_ids
|
364
|
-
group_ids
|
365
|
-
client_ids
|
366
|
-
)
|
380
|
+
encoded_data = transport_codec.encode({
|
381
|
+
"data" => data,
|
382
|
+
"user_ids" => user_ids,
|
383
|
+
"group_ids" => group_ids,
|
384
|
+
"client_ids" => client_ids
|
385
|
+
})
|
367
386
|
|
368
387
|
channel_opts = {}
|
369
388
|
|
@@ -512,12 +531,13 @@ module MessageBus::Implementation
|
|
512
531
|
end
|
513
532
|
|
514
533
|
# Stops listening for publications and stops executing scheduled tasks.
|
515
|
-
# Mostly used in tests to
|
534
|
+
# Mostly used in tests to destroy entire bus.
|
516
535
|
# @return [void]
|
517
536
|
def destroy
|
518
537
|
return if @destroyed
|
519
538
|
|
520
539
|
reliable_pub_sub.global_unsubscribe
|
540
|
+
reliable_pub_sub.destroy
|
521
541
|
|
522
542
|
@mutex.synchronize do
|
523
543
|
return if @destroyed
|
@@ -626,7 +646,7 @@ module MessageBus::Implementation
|
|
626
646
|
channel, site_id = decode_channel_name(msg.channel)
|
627
647
|
msg.channel = channel
|
628
648
|
msg.site_id = site_id
|
629
|
-
parsed =
|
649
|
+
parsed = transport_codec.decode(msg.data)
|
630
650
|
msg.data = parsed["data"]
|
631
651
|
msg.user_ids = parsed["user_ids"]
|
632
652
|
msg.group_ids = parsed["group_ids"]
|
data/message_bus.gemspec
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# -*- encoding: utf-8 -*-
|
3
2
|
|
4
3
|
require File.expand_path('../lib/message_bus/version', __FILE__)
|
5
4
|
|
@@ -8,7 +7,7 @@ Gem::Specification.new do |gem|
|
|
8
7
|
gem.email = ["sam.saffron@gmail.com"]
|
9
8
|
gem.description = %q{A message bus for rack}
|
10
9
|
gem.summary = %q{}
|
11
|
-
gem.homepage = "https://github.com/
|
10
|
+
gem.homepage = "https://github.com/discourse/message_bus"
|
12
11
|
gem.license = "MIT"
|
13
12
|
gem.files = `git ls-files`.split($\) +
|
14
13
|
["vendor/assets/javascripts/message-bus.js", "vendor/assets/javascripts/message-bus-ajax.js"]
|
@@ -17,8 +16,27 @@ Gem::Specification.new do |gem|
|
|
17
16
|
gem.name = "message_bus"
|
18
17
|
gem.require_paths = ["lib"]
|
19
18
|
gem.version = MessageBus::VERSION
|
20
|
-
gem.required_ruby_version = ">= 2.
|
19
|
+
gem.required_ruby_version = ">= 2.6.0"
|
20
|
+
|
21
21
|
gem.add_runtime_dependency 'rack', '>= 1.1.3'
|
22
|
+
|
23
|
+
# Optional runtime dependencies
|
22
24
|
gem.add_development_dependency 'redis'
|
23
25
|
gem.add_development_dependency 'pg'
|
26
|
+
gem.add_development_dependency 'concurrent-ruby' # for distributed-cache
|
27
|
+
|
28
|
+
gem.add_development_dependency 'minitest'
|
29
|
+
gem.add_development_dependency 'minitest-hooks'
|
30
|
+
gem.add_development_dependency 'minitest-global_expectations'
|
31
|
+
gem.add_development_dependency 'rake'
|
32
|
+
gem.add_development_dependency 'http_parser.rb'
|
33
|
+
gem.add_development_dependency 'thin'
|
34
|
+
gem.add_development_dependency 'rack-test'
|
35
|
+
gem.add_development_dependency 'puma'
|
36
|
+
gem.add_development_dependency 'm'
|
37
|
+
gem.add_development_dependency 'byebug'
|
38
|
+
gem.add_development_dependency 'oj'
|
39
|
+
gem.add_development_dependency 'yard'
|
40
|
+
gem.add_development_dependency 'rubocop-discourse'
|
41
|
+
gem.add_development_dependency 'rubocop-rspec'
|
24
42
|
end
|