message_bus 3.3.6 → 3.3.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.eslintrc.js +10 -2
- data/.github/workflows/ci.yml +36 -19
- data/CHANGELOG +15 -8
- data/DEV.md +0 -2
- data/Gemfile +0 -27
- data/LICENSE +1 -1
- data/README.md +10 -10
- data/Rakefile +12 -7
- data/assets/message-bus-ajax.js +3 -3
- data/bench/codecs/marshal.rb +1 -1
- data/bench/codecs/packed_string.rb +1 -1
- data/examples/bench/bench.lua +2 -2
- data/lib/message_bus/backends/base.rb +3 -3
- data/lib/message_bus/backends/postgres.rb +7 -3
- data/lib/message_bus/backends/redis.rb +1 -1
- data/lib/message_bus/client.rb +3 -7
- data/lib/message_bus/connection_manager.rb +1 -1
- data/lib/message_bus/distributed_cache.rb +2 -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 +6 -0
- data/lib/message_bus/rack/thin_ext.rb +1 -1
- data/lib/message_bus/version.rb +1 -1
- data/lib/message_bus.rb +6 -6
- data/message_bus.gemspec +20 -5
- data/package-lock.json +1575 -23
- data/package.json +7 -2
- data/spec/assets/SpecHelper.js +6 -5
- data/spec/assets/message-bus.spec.js +9 -6
- data/spec/helpers.rb +17 -6
- data/spec/integration/http_client_spec.rb +1 -1
- data/spec/lib/message_bus/backend_spec.rb +12 -44
- data/spec/lib/message_bus/client_spec.rb +6 -6
- data/spec/lib/message_bus/distributed_cache_spec.rb +5 -7
- data/spec/lib/message_bus/multi_process_spec.rb +1 -1
- data/spec/lib/message_bus/rack/middleware_spec.rb +16 -5
- data/spec/lib/message_bus_spec.rb +10 -6
- data/spec/spec_helper.rb +8 -9
- data/spec/support/jasmine-browser.json +16 -0
- metadata +220 -14
- data/spec/assets/support/jasmine.yml +0 -126
- data/spec/assets/support/jasmine_helper.rb +0 -11
- data/vendor/assets/javascripts/message-bus-ajax.js +0 -38
- data/vendor/assets/javascripts/message-bus.js +0 -549
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16601ac02268a477a94bf0347922162f66ce17dfdba1c4c655d576b46e78a79c
|
4
|
+
data.tar.gz: 746e2295f873d9cfe75c28b079b406bb42329a992146d414c63292c2148a8f48
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d048dde14c63d5abdda283571cb9c2be1b7fc809a94c7f0b4ec2eaa4785da03bc47535264741f65cfa1d66c75e1b0169ea0de39449456b9c791ba91518d62e9
|
7
|
+
data.tar.gz: 0cfbed1cab954e33805c94c7662c9094276615d5f338168da48d26f033da0f42685024b87aaee64d221e192d0592cd655fba7473da8d973616b218ce2858b045
|
data/.eslintrc.js
CHANGED
@@ -4,10 +4,18 @@ module.exports = {
|
|
4
4
|
browser: true,
|
5
5
|
es2021: false,
|
6
6
|
},
|
7
|
-
extends:
|
7
|
+
extends: 'eslint:recommended',
|
8
8
|
parserOptions: {
|
9
9
|
ecmaVersion: 2015,
|
10
|
-
sourceType:
|
10
|
+
sourceType: 'module',
|
11
11
|
},
|
12
12
|
rules: {},
|
13
|
+
ignorePatterns: [
|
14
|
+
'/vendor',
|
15
|
+
'/doc',
|
16
|
+
'/assets/babel.min.js',
|
17
|
+
'/assets/jquery-1.8.2.js',
|
18
|
+
'/assets/react-dom.js',
|
19
|
+
'/assets/react.js',
|
20
|
+
],
|
13
21
|
};
|
data/.github/workflows/ci.yml
CHANGED
@@ -4,7 +4,7 @@ on:
|
|
4
4
|
pull_request:
|
5
5
|
push:
|
6
6
|
branches:
|
7
|
-
-
|
7
|
+
- main
|
8
8
|
|
9
9
|
env:
|
10
10
|
PGHOST: localhost
|
@@ -15,40 +15,57 @@ env:
|
|
15
15
|
jobs:
|
16
16
|
build:
|
17
17
|
runs-on: ubuntu-latest
|
18
|
-
name: Ruby ${{ matrix.ruby }}
|
18
|
+
name: Ruby ${{ matrix.ruby }} (redis ${{ matrix.redis }})
|
19
|
+
timeout-minutes: 10
|
20
|
+
|
19
21
|
services:
|
20
22
|
postgres:
|
21
|
-
image: postgres:
|
23
|
+
image: postgres:14.0
|
22
24
|
env:
|
23
25
|
POSTGRES_PASSWORD: postgres
|
24
26
|
ports:
|
25
27
|
- 5432:5432
|
26
28
|
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
|
29
|
+
redis:
|
30
|
+
image: ${{ format('redis:{0}', matrix.redis) }}
|
31
|
+
ports:
|
32
|
+
- 6379:6379
|
33
|
+
options: >-
|
34
|
+
--health-cmd "redis-cli ping"
|
35
|
+
--health-interval 10s
|
36
|
+
--health-timeout 5s
|
37
|
+
--health-retries 5
|
38
|
+
|
27
39
|
strategy:
|
40
|
+
fail-fast: false
|
28
41
|
matrix:
|
29
|
-
ruby: ["
|
42
|
+
ruby: ["3.0", "2.7", "2.6"]
|
43
|
+
redis: ["5", "6"]
|
44
|
+
|
30
45
|
steps:
|
31
46
|
- uses: actions/checkout@v2
|
32
|
-
|
47
|
+
|
48
|
+
- uses: ruby/setup-ruby@v1
|
33
49
|
with:
|
34
50
|
ruby-version: ${{ matrix.ruby }}
|
35
|
-
|
36
|
-
|
51
|
+
bundler-cache: true # 'bundle install' and cache
|
52
|
+
|
53
|
+
- name: Set up Node.js
|
54
|
+
uses: actions/setup-node@v2
|
37
55
|
with:
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
56
|
+
node-version: 16
|
57
|
+
cache: npm
|
58
|
+
|
59
|
+
- name: Setup npm
|
60
|
+
run: npm install
|
61
|
+
|
42
62
|
- name: Create Database
|
43
63
|
run: |
|
44
64
|
createdb message_bus_test
|
45
|
-
|
46
|
-
uses: shogo82148/actions-setup-redis@v1
|
47
|
-
with:
|
48
|
-
redis-version: '5.x'
|
49
|
-
- name: Setup gems
|
50
|
-
run: |
|
51
|
-
bundle config path vendor/bundle
|
52
|
-
bundle install --jobs 4
|
65
|
+
|
53
66
|
- name: Tests
|
54
67
|
run: bundle exec rake
|
68
|
+
timeout-minutes: 3
|
69
|
+
|
70
|
+
- name: Linting
|
71
|
+
run: npx eslint .
|
data/CHANGELOG
CHANGED
@@ -1,10 +1,17 @@
|
|
1
|
+
15-12-2021
|
2
|
+
|
3
|
+
- Version 3.3.7
|
4
|
+
|
5
|
+
- FIX: Prevent simple polling from clobbering the session
|
6
|
+
- SECURITY: Fix path traversal on diagnostics route.
|
7
|
+
|
1
8
|
31-05-2021
|
2
9
|
|
3
10
|
- Version 3.3.6
|
4
11
|
|
5
12
|
- FEATURE: Introduce support for transport codecs
|
6
13
|
- FIX: event subscription leak in JS after start/stop/start sequence
|
7
|
-
- FEATURE: MessageBus.onVisibilityChange() can be used to trigger a
|
14
|
+
- FEATURE: MessageBus.onVisibilityChange() can be used to trigger a visibility change check by hand
|
8
15
|
|
9
16
|
28-04-2021
|
10
17
|
|
@@ -62,7 +69,7 @@
|
|
62
69
|
|
63
70
|
- Version 3.2.0
|
64
71
|
|
65
|
-
- FIX:
|
72
|
+
- FIX: compatibility with Rails 6.0.3, note: apps without ActionDispatch::Flash may stop working after this upgrade
|
66
73
|
to correct this disable middleware injection with `config.skip_message_bus_middleware = true` and configure middleware by hand with `app.middleware.use(MessageBus::Rack::Middleware)`
|
67
74
|
|
68
75
|
28-04-2020
|
@@ -189,7 +196,7 @@
|
|
189
196
|
|
190
197
|
- Version 2.1.6
|
191
198
|
|
192
|
-
- FEATURE: `
|
199
|
+
- FEATURE: `MessageBus.publish` accepts option `site_id` to publish to a site
|
193
200
|
- FEATURE: Added MessageBus::DistributedCache for cross process caching
|
194
201
|
- PERF: Use monotonic times in timer thread
|
195
202
|
- FEATURE: min poll interval is now configurable client side
|
@@ -253,7 +260,7 @@
|
|
253
260
|
|
254
261
|
- Version 2.0.6
|
255
262
|
|
256
|
-
- Fix: correct after_fork so it correctly
|
263
|
+
- Fix: correct after_fork so it correctly disconnects redis
|
257
264
|
- Fix: correct message_bus #destroy used in tests to clean up spec (deadlock)
|
258
265
|
- Fix: deliver backlog unconditionally when polling (and not long polling)
|
259
266
|
|
@@ -323,7 +330,7 @@
|
|
323
330
|
|
324
331
|
- Version 2.0.0.beta.6
|
325
332
|
|
326
|
-
- Feature: Support standalone
|
333
|
+
- Feature: Support standalone operation without depending on jQuery @nathanstitt
|
327
334
|
- Feature: Support a noconflict mode @nathanstitt
|
328
335
|
- Feature: Support JSON POST payload @nathanstitt
|
329
336
|
|
@@ -369,7 +376,7 @@
|
|
369
376
|
- Version 1.1.0
|
370
377
|
- Fix: keep track of client sequence on server, abandon old subscribes
|
371
378
|
- Fix: rare concurrency issue when subscribing concurrently
|
372
|
-
-
|
379
|
+
- Feature: remove most jQuery dependency from message-bus.js
|
373
380
|
|
374
381
|
09-07-2015
|
375
382
|
- Version 1.0.16
|
@@ -393,7 +400,7 @@
|
|
393
400
|
|
394
401
|
28-05-2015
|
395
402
|
- Version 1.0.12
|
396
|
-
- Feature: Support client_id
|
403
|
+
- Feature: Support client_id targeted message
|
397
404
|
|
398
405
|
06-05-2015
|
399
406
|
- Version 1.0.11
|
@@ -402,7 +409,7 @@
|
|
402
409
|
01-05-2015
|
403
410
|
- Version: 1.0.10
|
404
411
|
- Feature: no longer depends on EventMachine (only used for Thin backend)
|
405
|
-
- Feature:
|
412
|
+
- Feature: reliable pub sub will queue messages in memory if redis is readonly, configurable
|
406
413
|
- Fix: if redis is flushed we will continue to deliver messages
|
407
414
|
|
408
415
|
23-03-2015
|
data/DEV.md
CHANGED
data/Gemfile
CHANGED
@@ -3,30 +3,3 @@ source 'https://rubygems.org'
|
|
3
3
|
|
4
4
|
# Specify your gem's dependencies in message_bus.gemspec
|
5
5
|
gemspec
|
6
|
-
|
7
|
-
group :test do
|
8
|
-
gem 'minitest'
|
9
|
-
gem 'minitest-hooks'
|
10
|
-
gem 'minitest-global_expectations'
|
11
|
-
gem 'rake'
|
12
|
-
gem 'http_parser.rb'
|
13
|
-
gem 'thin'
|
14
|
-
gem 'rack-test', require: 'rack/test'
|
15
|
-
gem 'jasmine'
|
16
|
-
gem 'puma'
|
17
|
-
gem 'm'
|
18
|
-
end
|
19
|
-
|
20
|
-
group :test, :development do
|
21
|
-
gem 'byebug'
|
22
|
-
gem 'oj'
|
23
|
-
end
|
24
|
-
|
25
|
-
group :development do
|
26
|
-
gem 'yard'
|
27
|
-
gem 'rubocop-discourse', require: false
|
28
|
-
gem 'rubocop-rspec', require: false
|
29
|
-
end
|
30
|
-
|
31
|
-
gem 'rack'
|
32
|
-
gem 'concurrent-ruby' # for distributed-cache
|
data/LICENSE
CHANGED
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
19
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
20
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
21
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -12,7 +12,7 @@ Read the generated docs: <https://www.rubydoc.info/gems/message_bus>
|
|
12
12
|
|
13
13
|
## Ruby version support
|
14
14
|
|
15
|
-
MessageBus only support officially supported versions of Ruby; as of [
|
15
|
+
MessageBus only support officially supported versions of Ruby; as of [2021-03-31](https://www.ruby-lang.org/en/downloads/branches/) this means we only support Ruby version 2.6 and up.
|
16
16
|
|
17
17
|
## Can you handle concurrent requests?
|
18
18
|
|
@@ -68,19 +68,19 @@ id = MessageBus.last_id("/channel")
|
|
68
68
|
MessageBus.backlog "/channel", id
|
69
69
|
```
|
70
70
|
|
71
|
-
###
|
71
|
+
### Targeted messages
|
72
72
|
|
73
|
-
Messages can be
|
73
|
+
Messages can be targeted to particular clients by supplying the `client_ids` option when publishing a message.
|
74
74
|
|
75
75
|
```ruby
|
76
76
|
MessageBus.publish "/channel", "hello", client_ids: ["XXX", "YYY"] # (using MessageBus.clientId)
|
77
77
|
```
|
78
78
|
|
79
|
-
By configuring the `user_id_lookup` and `group_ids_lookup` options with a Proc or Lambda which will be called with a [Rack specification environment](https://github.com/rack/rack/blob/master/SPEC.rdoc#the-environment-), messages can be
|
79
|
+
By configuring the `user_id_lookup` and `group_ids_lookup` options with a Proc or Lambda which will be called with a [Rack specification environment](https://github.com/rack/rack/blob/master/SPEC.rdoc#the-environment-), messages can be targeted to particular clients users or groups by supplying either the `user_ids` or `group_ids` options when publishing a message.
|
80
80
|
|
81
81
|
```ruby
|
82
82
|
MessageBus.configure(user_id_lookup: proc do |env|
|
83
|
-
# this lookup occurs on JS-client
|
83
|
+
# this lookup occurs on JS-client polling, so that server can retrieve backlog
|
84
84
|
# for the client considering/matching/filtering user_ids set on published messages
|
85
85
|
# if user_id is not set on publish time, any user_id returned here will receive the message
|
86
86
|
# return the user id here
|
@@ -98,7 +98,7 @@ end)
|
|
98
98
|
MessageBus.publish "/channel", "hello", group_ids: [1, 2, 3]
|
99
99
|
|
100
100
|
# example of MessageBus to set user_ids from an initializer in Rails and Devise:
|
101
|
-
# config/
|
101
|
+
# config/initializers/message_bus.rb
|
102
102
|
MessageBus.user_id_lookup do |env|
|
103
103
|
req = Rack::Request.new(env)
|
104
104
|
|
@@ -109,13 +109,13 @@ MessageBus.user_id_lookup do |env|
|
|
109
109
|
end
|
110
110
|
```
|
111
111
|
|
112
|
-
If both `user_ids` and `group_ids` options are supplied when publishing a message, the message will be
|
112
|
+
If both `user_ids` and `group_ids` options are supplied when publishing a message, the message will be targeted at clients with lookup return values that matches on either the `user_ids` **or** the `group_ids` options.
|
113
113
|
|
114
114
|
```ruby
|
115
115
|
MessageBus.publish "/channel", "hello", user_ids: [1, 2, 3], group_ids: [1, 2, 3]
|
116
116
|
```
|
117
117
|
|
118
|
-
If the `client_ids` option is supplied with either the `user_ids` or `group_ids` options when
|
118
|
+
If the `client_ids` option is supplied with either the `user_ids` or `group_ids` options when publishing a message, the `client_ids` option will be applied unconditionally and messages will be filtered further using `user_id` or `group_id` clauses.
|
119
119
|
|
120
120
|
```ruby
|
121
121
|
MessageBus.publish "/channel", "hello", client_ids: ["XXX", "YYY"], user_ids: [1, 2, 3], group_ids: [1, 2, 3]
|
@@ -245,7 +245,7 @@ end)
|
|
245
245
|
MessageBus.publish "/channel", "some message"
|
246
246
|
|
247
247
|
# you can also choose to pass the `:site_id`.
|
248
|
-
# This takes
|
248
|
+
# This takes precedence over whatever `site_id_lookup`
|
249
249
|
# returns
|
250
250
|
MessageBus.publish "/channel", "some message", site_id: "site-id"
|
251
251
|
|
@@ -454,7 +454,7 @@ using a packed string encoder.
|
|
454
454
|
|
455
455
|
Keep in mind, much of MessageBus internals and supporting tools expect data to be converted to JSON and back, if you use a naive (and fast) `Marshal` based codec you may need to limit the features you use. Specifically the Postgresql backend expects the codec never to return a string with `\u0000`, additionally some classes like DistributedCache expect keys to be converted to Strings.
|
456
456
|
|
457
|
-
Another example may be very large and complicated messages where Oj in
|
457
|
+
Another example may be very large and complicated messages where Oj in compatibility mode outperforms JSON. To opt for the Oj codec use:
|
458
458
|
|
459
459
|
```
|
460
460
|
MessageBus.configure(transport_codec: MessageBus::Codec::Oj.new)
|
data/Rakefile
CHANGED
@@ -4,12 +4,8 @@ require 'rake/testtask'
|
|
4
4
|
require 'bundler'
|
5
5
|
require 'bundler/gem_tasks'
|
6
6
|
require 'bundler/setup'
|
7
|
-
require 'jasmine'
|
8
|
-
|
9
|
-
ENV['JASMINE_CONFIG_PATH'] ||= File.join(Dir.pwd, 'spec', 'assets', 'support', 'jasmine.yml')
|
10
|
-
load 'jasmine/tasks/jasmine.rake'
|
11
|
-
|
12
7
|
require 'rubocop/rake_task'
|
8
|
+
|
13
9
|
RuboCop::RakeTask.new
|
14
10
|
|
15
11
|
require 'yard'
|
@@ -35,7 +31,14 @@ module Bundler
|
|
35
31
|
end
|
36
32
|
end
|
37
33
|
|
38
|
-
|
34
|
+
namespace :jasmine do
|
35
|
+
desc "Run Jasmine tests in headless mode"
|
36
|
+
task 'ci' do
|
37
|
+
if !system("npx jasmine-browser-runner runSpecs")
|
38
|
+
exit 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
39
42
|
|
40
43
|
backends = Dir["lib/message_bus/backends/*.rb"].map { |file| file.match(%r{backends/(?<backend>.*).rb})[:backend] } - ["base"]
|
41
44
|
|
@@ -57,6 +60,8 @@ namespace :spec do
|
|
57
60
|
|
58
61
|
desc "Run integration tests"
|
59
62
|
task :integration do
|
63
|
+
require "socket"
|
64
|
+
|
60
65
|
def port_available?(port)
|
61
66
|
server = TCPServer.open("0.0.0.0", port)
|
62
67
|
server.close
|
@@ -78,7 +83,7 @@ namespace :spec do
|
|
78
83
|
end
|
79
84
|
|
80
85
|
desc "Run tests on all backends, plus client JS tests"
|
81
|
-
task spec: backends.map { |backend| "spec:#{backend}" } + [:
|
86
|
+
task spec: backends.map { |backend| "spec:#{backend}" } + ["jasmine:ci", "spec:integration"]
|
82
87
|
|
83
88
|
desc "Run performance benchmarks on all backends"
|
84
89
|
task :performance do
|
data/assets/message-bus-ajax.js
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
// as a fallback if jQuery is not present
|
3
3
|
//
|
4
4
|
// Only implements methods & options used by MessageBus
|
5
|
-
(function(global
|
5
|
+
(function(global) {
|
6
6
|
'use strict';
|
7
7
|
if (!global.MessageBus){
|
8
8
|
throw new Error("MessageBus must be loaded before the ajax adapter");
|
@@ -16,7 +16,7 @@
|
|
16
16
|
for (var name in options.headers){
|
17
17
|
xhr.setRequestHeader(name, options.headers[name]);
|
18
18
|
}
|
19
|
-
xhr.setRequestHeader('Content-Type', 'application/
|
19
|
+
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
20
20
|
if (options.messageBus.chunked){
|
21
21
|
options.messageBus.onProgressListener(xhr);
|
22
22
|
}
|
@@ -31,7 +31,7 @@
|
|
31
31
|
options.complete();
|
32
32
|
}
|
33
33
|
}
|
34
|
-
xhr.send(
|
34
|
+
xhr.send(new URLSearchParams(options.data).toString());
|
35
35
|
return xhr;
|
36
36
|
};
|
37
37
|
|
data/bench/codecs/marshal.rb
CHANGED
data/examples/bench/bench.lua
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
-- wrk returns lots of read errors, this is unavoidable cause
|
2
2
|
--
|
3
|
-
-- 1. There is no internal
|
3
|
+
-- 1. There is no internal implementation of chunked encoding in wrk (which would be ideal)
|
4
4
|
--
|
5
5
|
-- 2. MessageBus gem does not provide http keepalive (by design), and can not provide content length
|
6
|
-
-- if MessageBus provided keepalive it would have to be able to
|
6
|
+
-- if MessageBus provided keepalive it would have to be able to re-dispatch requests to rack, something
|
7
7
|
-- that is not supported by the underlying rack hijack protocol, once a req is hijacked it can not be
|
8
8
|
-- returned
|
9
9
|
--
|
@@ -62,7 +62,7 @@ module MessageBus
|
|
62
62
|
attr_accessor :max_backlog_size
|
63
63
|
# @return [Integer] the largest permitted size (number of messages) for the global backlog; beyond this capacity, old messages will be dropped.
|
64
64
|
attr_accessor :max_global_backlog_size
|
65
|
-
# @return [Integer] the longest amount of time a message may live in a backlog before
|
65
|
+
# @return [Integer] the longest amount of time a message may live in a backlog before being removed, in seconds.
|
66
66
|
attr_accessor :max_backlog_age
|
67
67
|
# Typically, backlogs are trimmed whenever we publish to them. This setting allows some tolerance in order to improve performance.
|
68
68
|
# @return [Integer] the interval of publications between which the backlog will not be cleared.
|
@@ -74,7 +74,7 @@ module MessageBus
|
|
74
74
|
# @param [Integer] max_backlog_size the largest permitted size (number of messages) for per-channel backlogs; beyond this capacity, old messages will be dropped.
|
75
75
|
def initialize(config = {}, max_backlog_size = 1000); end
|
76
76
|
|
77
|
-
# Performs routines specific to the backend that are necessary after a process fork, typically
|
77
|
+
# Performs routines specific to the backend that are necessary after a process fork, typically triggered by a forking webserver. Typically this re-opens sockets to the backend.
|
78
78
|
def after_fork
|
79
79
|
raise ConcreteClassMustImplementError
|
80
80
|
end
|
@@ -96,7 +96,7 @@ module MessageBus
|
|
96
96
|
# @param [JSON] data some data to publish to the channel. Must be an object that can be encoded as JSON
|
97
97
|
# @param [Hash] opts
|
98
98
|
# @option opts [Boolean] :queue_in_memory (true) whether or not to hold the message in an in-memory buffer if publication fails, to be re-tried later
|
99
|
-
# @option opts [Integer] :max_backlog_age (`self.max_backlog_age`) the longest amount of time a message may live in a backlog before
|
99
|
+
# @option opts [Integer] :max_backlog_age (`self.max_backlog_age`) the longest amount of time a message may live in a backlog before being removed, in seconds
|
100
100
|
# @option opts [Integer] :max_backlog_size (`self.max_backlog_size`) the largest permitted size (number of messages) for the channel backlog; beyond this capacity, old messages will be dropped
|
101
101
|
#
|
102
102
|
# @return [Integer] the channel-specific ID the message was given
|
@@ -44,6 +44,7 @@ module MessageBus
|
|
44
44
|
@listening_on = {}
|
45
45
|
@available = []
|
46
46
|
@allocated = {}
|
47
|
+
@subscribe_connection = nil
|
47
48
|
@mutex = Mutex.new
|
48
49
|
@pid = Process.pid
|
49
50
|
end
|
@@ -131,7 +132,7 @@ module MessageBus
|
|
131
132
|
listener = Listener.new
|
132
133
|
yield listener
|
133
134
|
|
134
|
-
conn = raw_pg_connection
|
135
|
+
conn = @subscribe_connection = raw_pg_connection
|
135
136
|
conn.exec "LISTEN #{channel}"
|
136
137
|
listener.do_sub.call
|
137
138
|
while listening_on?(channel, obj)
|
@@ -145,6 +146,9 @@ module MessageBus
|
|
145
146
|
|
146
147
|
conn.exec "UNLISTEN #{channel}"
|
147
148
|
nil
|
149
|
+
ensure
|
150
|
+
@subscribe_connection&.close
|
151
|
+
@subscribe_connection = nil
|
148
152
|
end
|
149
153
|
|
150
154
|
def unsubscribe
|
@@ -251,7 +255,7 @@ module MessageBus
|
|
251
255
|
@clear_every = config[:clear_every] || 1
|
252
256
|
end
|
253
257
|
|
254
|
-
# Reconnects to Postgres; used after a process fork, typically
|
258
|
+
# Reconnects to Postgres; used after a process fork, typically triggered by a forking webserver
|
255
259
|
# @see Base#after_fork
|
256
260
|
def after_fork
|
257
261
|
client.reconnect
|
@@ -277,7 +281,7 @@ module MessageBus
|
|
277
281
|
msg = MessageBus::Message.new backlog_id, backlog_id, channel, data
|
278
282
|
payload = msg.encode
|
279
283
|
c.publish postgresql_channel_name, payload
|
280
|
-
if backlog_id % clear_every == 0
|
284
|
+
if backlog_id && backlog_id % clear_every == 0
|
281
285
|
max_backlog_size = (opts && opts[:max_backlog_size]) || self.max_backlog_size
|
282
286
|
max_backlog_age = (opts && opts[:max_backlog_age]) || self.max_backlog_age
|
283
287
|
c.clear_global_backlog(backlog_id, @max_global_backlog_size)
|
@@ -62,7 +62,7 @@ module MessageBus
|
|
62
62
|
@max_backlog_age = 604800
|
63
63
|
end
|
64
64
|
|
65
|
-
# Reconnects to Redis; used after a process fork, typically
|
65
|
+
# Reconnects to Redis; used after a process fork, typically triggered by a forking webserver
|
66
66
|
# @see Base#after_fork
|
67
67
|
def after_fork
|
68
68
|
pub_redis.disconnect!
|
data/lib/message_bus/client.rb
CHANGED
@@ -220,7 +220,7 @@ class MessageBus::Client
|
|
220
220
|
|
221
221
|
private
|
222
222
|
|
223
|
-
# heavily optimised to avoid all
|
223
|
+
# heavily optimised to avoid all unneeded allocations
|
224
224
|
NEWLINE = "\r\n".freeze
|
225
225
|
COLON_SPACE = ": ".freeze
|
226
226
|
HTTP_11 = "HTTP/1.1 200 OK\r\n".freeze
|
@@ -261,7 +261,7 @@ class MessageBus::Client
|
|
261
261
|
@wrote_headers = true
|
262
262
|
end
|
263
263
|
|
264
|
-
# chunked encoding may be "re-chunked" by proxies, so add a
|
264
|
+
# chunked encoding may be "re-chunked" by proxies, so add a separator
|
265
265
|
postfix = NEWLINE + "|" + NEWLINE
|
266
266
|
data = data.gsub(postfix, NEWLINE + "||" + NEWLINE)
|
267
267
|
chunk_length = data.bytesize + postfix.bytesize
|
@@ -275,11 +275,7 @@ class MessageBus::Client
|
|
275
275
|
@async_response << postfix
|
276
276
|
@async_response << NEWLINE
|
277
277
|
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)
|
278
|
+
@io.write(chunk_length.to_s(16) << NEWLINE << data << postfix << NEWLINE)
|
283
279
|
end
|
284
280
|
end
|
285
281
|
|
@@ -45,7 +45,8 @@ module MessageBus
|
|
45
45
|
hash = current.hash(message.site_id || DEFAULT_SITE_ID)
|
46
46
|
|
47
47
|
case payload["op"]
|
48
|
-
|
48
|
+
# TODO: consider custom marshal support with a restricted set
|
49
|
+
when "set" then hash[payload["key"]] = payload["marshalled"] ? Marshal.load(Base64.decode64(payload["value"])) : payload["value"] # rubocop:disable Security/MarshalLoad
|
49
50
|
when "delete" then hash.delete(payload["key"])
|
50
51
|
when "clear" then hash.clear
|
51
52
|
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)
|