message_bus 2.0.0.beta.2 → 2.0.0.beta.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of message_bus might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +10 -2
- data/CHANGELOG +10 -0
- data/Gemfile +1 -6
- data/README.md +43 -16
- data/Rakefile +18 -4
- data/lib/message_bus.rb +64 -47
- data/lib/message_bus/backends/postgres.rb +396 -0
- data/lib/message_bus/{redis/reliable_pub_sub.rb → backends/redis.rb} +1 -0
- data/lib/message_bus/rack/middleware.rb +14 -5
- data/lib/message_bus/version.rb +1 -1
- data/message_bus.gemspec +3 -1
- data/spec/lib/message_bus/assets/asset_encoding_spec.rb +4 -4
- data/spec/lib/message_bus/backends/postgres_spec.rb +208 -0
- data/spec/lib/message_bus/{redis/reliable_pub_sub_spec.rb → backends/redis_spec.rb} +25 -23
- data/spec/lib/message_bus/client_spec.rb +28 -27
- data/spec/lib/message_bus/connection_manager_spec.rb +22 -24
- data/spec/lib/message_bus/multi_process_spec.rb +54 -27
- data/spec/lib/message_bus/rack/middleware_spec.rb +81 -38
- data/spec/lib/message_bus/timer_thread_spec.rb +6 -6
- data/spec/lib/message_bus_spec.rb +36 -35
- data/spec/spec_helper.rb +16 -21
- metadata +24 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13a3191447206ef44053ab24b6ae199b7e18d11e
|
4
|
+
data.tar.gz: 2b5037efdc6052aec3e6087461b26d5902ea0971
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a3d536e64f1efd37eec538cbef41b794a083cb9516d4457b26d0c2b4d24af886162720a46896951e6921333be15abce7c573898ac0b277a38f90681b1612a1e
|
7
|
+
data.tar.gz: 9aabc10913a3816708fc808893d98cfea290940af41b0ab19478633db2abfcdc2091df8c8140c3fdfc9f82ea3e7f27970688c0310536003bb259dd3c3db7e14c
|
data/.travis.yml
CHANGED
@@ -3,9 +3,17 @@ language: ruby
|
|
3
3
|
rvm:
|
4
4
|
- 1.9.3
|
5
5
|
- 2.0.0
|
6
|
-
- 2.1.
|
7
|
-
- 2.2
|
6
|
+
- 2.1.8
|
7
|
+
- 2.2.4
|
8
|
+
- 2.3.0
|
8
9
|
gemfile:
|
9
10
|
- Gemfile
|
11
|
+
addons:
|
12
|
+
postgresql: "9.4"
|
13
|
+
env:
|
14
|
+
- PGUSER=postgres
|
15
|
+
before_script:
|
16
|
+
- psql -c 'create database message_bus_test;' -U postgres
|
10
17
|
services:
|
11
18
|
- redis-server
|
19
|
+
- postgresql
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
29-02-2016
|
2
|
+
|
3
|
+
- Version 2.0.0.beta.3
|
4
|
+
|
5
|
+
- Feature: Postgresql backend @jeremyevans
|
6
|
+
- Breaking Change: Configuration API changed see Readme for details @jeremyevans
|
7
|
+
- Breaking Change: Remove runtime dependency on Redis @jeremyevans
|
8
|
+
- Dev: Convert all specs to minitest @jeremyevans
|
9
|
+
- Feature: Support passing channels to Rack middleware via env['message_bus.channels'] via @jeremyevans
|
10
|
+
|
1
11
|
03-01-2016
|
2
12
|
|
3
13
|
- Version 2.0.0.beta.2
|
data/Gemfile
CHANGED
@@ -4,13 +4,8 @@ source 'https://rubygems.org'
|
|
4
4
|
gemspec
|
5
5
|
|
6
6
|
group :test do
|
7
|
-
gem '
|
8
|
-
gem 'redis'
|
7
|
+
gem 'minitest'
|
9
8
|
gem 'rake'
|
10
|
-
gem 'rbtrace'
|
11
|
-
gem 'guard-rspec'
|
12
|
-
gem 'rb-inotify', require: RUBY_PLATFORM =~ /linux/i ? 'rb-inotify' : false
|
13
|
-
gem 'rack'
|
14
9
|
gem 'http_parser.rb'
|
15
10
|
gem 'thin'
|
16
11
|
gem 'rack-test', require: 'rack/test'
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# MessageBus
|
2
2
|
|
3
|
-
A reliable, robust messaging bus for Ruby processes and web clients
|
3
|
+
A reliable, robust messaging bus for Ruby processes and web clients.
|
4
4
|
|
5
5
|
MessageBus implements a Server to Server channel based protocol and Server to Web Client protocol (using polling, long-polling or long-polling + streaming)
|
6
6
|
|
@@ -49,21 +49,21 @@ MessageBus.backlog "/channel", id
|
|
49
49
|
# returns all messages after the id
|
50
50
|
|
51
51
|
# messages can be targetted at particular users or groups
|
52
|
-
MessageBus.publish "/channel", user_ids: [1,2,3], group_ids: [4,5,6]
|
52
|
+
MessageBus.publish "/channel", "hello", user_ids: [1,2,3], group_ids: [4,5,6]
|
53
53
|
|
54
54
|
# messages can be targetted at particular clients (using MessageBus.clientId)
|
55
|
-
MessageBus.publish "/channel", client_ids: ["XXX","YYY"]
|
55
|
+
MessageBus.publish "/channel", "hello", client_ids: ["XXX","YYY"]
|
56
56
|
|
57
57
|
# message bus determines the user ids and groups based on env
|
58
58
|
|
59
|
-
MessageBus.user_id_lookup do |env|
|
59
|
+
MessageBus.configure(user_id_lookup: proc do |env|
|
60
60
|
# return the user id here
|
61
|
-
end
|
61
|
+
end)
|
62
62
|
|
63
|
-
MessageBus.group_ids_lookup do |env|
|
63
|
+
MessageBus.configure(group_ids_lookup: proc do |env|
|
64
64
|
# return the group ids the user belongs to
|
65
65
|
# can be nil or []
|
66
|
-
end
|
66
|
+
end)
|
67
67
|
```
|
68
68
|
|
69
69
|
### Transport
|
@@ -100,7 +100,7 @@ MessageBus.enableChunkedEncoding = false; // in your JavaScript
|
|
100
100
|
Or
|
101
101
|
|
102
102
|
```
|
103
|
-
MessageBus.chunked_encoding_enabled
|
103
|
+
MessageBus.configure(chunked_encoding_enabled: false) // in Ruby
|
104
104
|
```
|
105
105
|
|
106
106
|
Long Polling requires no special setup, as soon as new data arrives on the channel the server delivers the data and closes the connection.
|
@@ -113,9 +113,9 @@ MessageBus can be used in an environment that hosts multiple sites by multiplexi
|
|
113
113
|
|
114
114
|
```ruby
|
115
115
|
# define a site_id lookup method
|
116
|
-
MessageBus.site_id_lookup do
|
116
|
+
MessageBus.configure(site_id_lookup: proc do
|
117
117
|
some_method_that_returns_site_id_string
|
118
|
-
end
|
118
|
+
end)
|
119
119
|
|
120
120
|
# you may post messages just to this site
|
121
121
|
MessageBus.publish "/channel", "some message"
|
@@ -137,6 +137,11 @@ JavaScript can listen on any channel (and receive notification via polling or lo
|
|
137
137
|
```
|
138
138
|
Note, the message-bus.js file is located in the assets folder.
|
139
139
|
|
140
|
+
**Rails**
|
141
|
+
```javascript
|
142
|
+
//= require message-bus
|
143
|
+
```
|
144
|
+
|
140
145
|
```javascript
|
141
146
|
MessageBus.start(); // call once at startup
|
142
147
|
|
@@ -148,6 +153,10 @@ MessageBus.subscribe("/channel", function(data){
|
|
148
153
|
|
149
154
|
```
|
150
155
|
|
156
|
+
There is also a Ruby implementation of the client library, at
|
157
|
+
[message_bus-client](https://github.com/lowjoel/message_bus-client) with the API very similar to
|
158
|
+
that of the JavaScript client.
|
159
|
+
|
151
160
|
**Client settings**:
|
152
161
|
|
153
162
|
|
@@ -179,6 +188,13 @@ ajax|$.ajax|The only dependency on jQuery, you may set up a custom ajax function
|
|
179
188
|
|
180
189
|
`MessageBus.unsubscribe(channel,func)` : Unsubscribe callback from a particular channel
|
181
190
|
|
191
|
+
## Running tests
|
192
|
+
|
193
|
+
To run tests you need both Postgres and Redis installed. By default we will connect to the database `message_bus_test` with the current username. If you wish to override this:
|
194
|
+
|
195
|
+
```
|
196
|
+
PGUSER=some_user PGDATABASE=some_db bundle exec rake
|
197
|
+
```
|
182
198
|
|
183
199
|
|
184
200
|
## Configuration
|
@@ -188,13 +204,23 @@ ajax|$.ajax|The only dependency on jQuery, you may set up a custom ajax function
|
|
188
204
|
You can configure redis setting in `config/initializers/message_bus.rb`, like
|
189
205
|
|
190
206
|
```ruby
|
191
|
-
MessageBus.
|
207
|
+
MessageBus.configure(backend: :redis, url: "redis://:p4ssw0rd@10.0.1.1:6380/15")
|
192
208
|
```
|
193
209
|
The redis client message_bus uses is [redis-rb](https://github.com/redis/redis-rb), so you can visit it's repo to see what options you can configure.
|
194
210
|
|
211
|
+
### PostgreSQL
|
212
|
+
|
213
|
+
message_bus also supports PostgreSQL as the backend:
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
MessageBus.configure(backend: :postgres, backend_options: {user: 'message_bus', dbname: 'message_bus'})
|
217
|
+
```
|
218
|
+
|
219
|
+
The PostgreSQL client message_bus uses is [ruby-pg](https://bitbucket.org/ged/ruby-pg), so you can visit it's repo to see what options you can configure.
|
220
|
+
|
195
221
|
### Forking/threading app servers
|
196
222
|
|
197
|
-
If you're using a forking or threading app server and you're not getting immediate updates from published messages, you might need to reconnect Redis in your app server config:
|
223
|
+
If you're using a forking or threading app server and you're not getting immediate updates from published messages, you might need to reconnect Redis/PostgreSQL in your app server config:
|
198
224
|
|
199
225
|
#### Passenger
|
200
226
|
```ruby
|
@@ -229,14 +255,15 @@ after_fork do |server, worker|
|
|
229
255
|
end
|
230
256
|
```
|
231
257
|
|
258
|
+
###
|
259
|
+
|
232
260
|
## Want to help?
|
233
261
|
|
234
262
|
If you are looking to contribute to this project here are some ideas
|
235
263
|
|
236
|
-
- Build
|
237
|
-
-
|
238
|
-
- Improve general documentation
|
239
|
-
- Port the test suite to MiniTest
|
264
|
+
- Build backends for other providers (zeromq, rabbitmq, disque)
|
265
|
+
- Improve and properly document admin dashboard (add opt-in stats, better diagnostics into queues)
|
266
|
+
- Improve general documentation (Add examples, refine existing examples)
|
240
267
|
- Make MessageBus a nice website
|
241
268
|
|
242
269
|
|
data/Rakefile
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
require 'rake/testtask'
|
2
3
|
require 'bundler'
|
3
4
|
require 'bundler/gem_tasks'
|
4
5
|
require 'bundler/setup'
|
@@ -7,8 +8,21 @@ Bundler.require(:default, :test)
|
|
7
8
|
|
8
9
|
task :default => [:spec]
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
run_spec = proc do |backend|
|
12
|
+
begin
|
13
|
+
ENV['MESSAGE_BUS_BACKEND'] = backend
|
14
|
+
sh "#{FileUtils::RUBY} -e \"ARGV.each{|f| load f}\" #{Dir['spec/**/*_spec.rb'].to_a.join(' ')}"
|
15
|
+
ensure
|
16
|
+
ENV.delete('MESSAGE_BUS_BACKEND')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
task :spec => [:spec_redis, :spec_postgres]
|
21
|
+
|
22
|
+
task :spec_redis do
|
23
|
+
run_spec.call('redis')
|
24
|
+
end
|
25
|
+
|
26
|
+
task :spec_postgres do
|
27
|
+
run_spec.call('postgres')
|
14
28
|
end
|
data/lib/message_bus.rb
CHANGED
@@ -7,7 +7,6 @@ require "message_bus/connection_manager"
|
|
7
7
|
require "message_bus/diagnostics"
|
8
8
|
require "message_bus/rack/middleware"
|
9
9
|
require "message_bus/rack/diagnostics"
|
10
|
-
require "message_bus/redis/reliable_pub_sub"
|
11
10
|
require "message_bus/timer_thread"
|
12
11
|
|
13
12
|
# we still need to take care of the logger
|
@@ -16,10 +15,13 @@ if defined?(::Rails)
|
|
16
15
|
end
|
17
16
|
|
18
17
|
module MessageBus; end
|
18
|
+
MessageBus::BACKENDS = {}
|
19
19
|
class MessageBus::InvalidMessage < StandardError; end
|
20
20
|
class MessageBus::BusDestroyed < StandardError; end
|
21
21
|
|
22
22
|
module MessageBus::Implementation
|
23
|
+
# Configuration options hash
|
24
|
+
attr_reader :config
|
23
25
|
|
24
26
|
# Like Mutex but safe for recursive calls
|
25
27
|
class Synchronizer
|
@@ -27,87 +29,90 @@ module MessageBus::Implementation
|
|
27
29
|
end
|
28
30
|
|
29
31
|
def initialize
|
32
|
+
@config = {}
|
30
33
|
@mutex = Synchronizer.new
|
31
34
|
end
|
32
35
|
|
33
36
|
def cache_assets=(val)
|
34
|
-
|
37
|
+
configure(cache_assets: val)
|
35
38
|
end
|
36
39
|
|
37
40
|
def cache_assets
|
38
|
-
if defined? @cache_assets
|
39
|
-
@cache_assets
|
41
|
+
if defined? @config[:cache_assets]
|
42
|
+
@config[:cache_assets]
|
40
43
|
else
|
41
44
|
true
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
45
48
|
def logger=(logger)
|
46
|
-
|
49
|
+
configure(logger: logger)
|
47
50
|
end
|
48
51
|
|
49
52
|
def logger
|
50
|
-
return @logger if @logger
|
53
|
+
return @config[:logger] if @config[:logger]
|
51
54
|
require 'logger'
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
+
logger = Logger.new(STDOUT)
|
56
|
+
logger.level = Logger::INFO
|
57
|
+
configure(logger: logger)
|
58
|
+
logger
|
55
59
|
end
|
56
60
|
|
57
61
|
def chunked_encoding_enabled?
|
58
|
-
@chunked_encoding_enabled == false ? false : true
|
62
|
+
@config[:chunked_encoding_enabled] == false ? false : true
|
59
63
|
end
|
60
64
|
|
61
65
|
def chunked_encoding_enabled=(val)
|
62
|
-
|
66
|
+
configure(chunked_encoding_enabled: val)
|
63
67
|
end
|
64
68
|
|
65
69
|
def long_polling_enabled?
|
66
|
-
@long_polling_enabled == false ? false : true
|
70
|
+
@config[:long_polling_enabled] == false ? false : true
|
67
71
|
end
|
68
72
|
|
69
73
|
def long_polling_enabled=(val)
|
70
|
-
|
74
|
+
configure(long_polling_enabled: val)
|
71
75
|
end
|
72
76
|
|
73
77
|
# The number of simultanuous clients we can service
|
74
78
|
# will revert to polling if we are out of slots
|
75
79
|
def max_active_clients=(val)
|
76
|
-
|
80
|
+
configure(max_active_clients: val)
|
77
81
|
end
|
78
82
|
|
79
83
|
def max_active_clients
|
80
|
-
@max_active_clients || 1000
|
84
|
+
@config[:max_active_clients] || 1000
|
81
85
|
end
|
82
86
|
|
83
87
|
def rack_hijack_enabled?
|
84
|
-
if @rack_hijack_enabled.nil?
|
85
|
-
|
88
|
+
if @config[:rack_hijack_enabled].nil?
|
89
|
+
enable = true
|
86
90
|
|
87
91
|
# without this switch passenger will explode
|
88
92
|
# it will run out of connections after about 10
|
89
93
|
if defined? PhusionPassenger
|
90
|
-
|
94
|
+
enable = false
|
91
95
|
if PhusionPassenger.respond_to? :advertised_concurrency_level
|
92
96
|
PhusionPassenger.advertised_concurrency_level = 0
|
93
|
-
|
97
|
+
enable = true
|
94
98
|
end
|
95
99
|
end
|
100
|
+
configure(rack_hijack_enabled: enable)
|
96
101
|
end
|
97
102
|
|
98
|
-
@rack_hijack_enabled
|
103
|
+
@config[:rack_hijack_enabled]
|
99
104
|
end
|
100
105
|
|
101
106
|
def rack_hijack_enabled=(val)
|
102
|
-
|
107
|
+
configure(rack_hijack_enabled: val)
|
103
108
|
end
|
104
109
|
|
105
110
|
def long_polling_interval=(millisecs)
|
106
|
-
|
111
|
+
configure(long_polling_interval: millisecs)
|
107
112
|
end
|
108
113
|
|
109
114
|
def long_polling_interval
|
110
|
-
@long_polling_interval || 25 * 1000
|
115
|
+
@config[:long_polling_interval] || 25 * 1000
|
111
116
|
end
|
112
117
|
|
113
118
|
def off
|
@@ -118,56 +123,58 @@ module MessageBus::Implementation
|
|
118
123
|
@off = false
|
119
124
|
end
|
120
125
|
|
126
|
+
def configure(config)
|
127
|
+
@config.merge!(config)
|
128
|
+
end
|
129
|
+
|
121
130
|
# Allow us to inject a redis db
|
122
131
|
def redis_config=(config)
|
123
|
-
|
132
|
+
configure(config.merge(:backend=>:redis))
|
124
133
|
end
|
125
134
|
|
126
|
-
|
127
|
-
@redis_config ||= {}
|
128
|
-
end
|
135
|
+
alias redis_config config
|
129
136
|
|
130
137
|
def site_id_lookup(&blk)
|
131
|
-
|
132
|
-
@site_id_lookup
|
138
|
+
configure(site_id_lookup: blk) if blk
|
139
|
+
@config[:site_id_lookup]
|
133
140
|
end
|
134
141
|
|
135
142
|
def user_id_lookup(&blk)
|
136
|
-
|
137
|
-
@user_id_lookup
|
143
|
+
configure(user_id_lookup: blk) if blk
|
144
|
+
@config[:user_id_lookup]
|
138
145
|
end
|
139
146
|
|
140
147
|
def group_ids_lookup(&blk)
|
141
|
-
|
142
|
-
@group_ids_lookup
|
148
|
+
configure(group_ids_lookup: blk) if blk
|
149
|
+
@config[:group_ids_lookup]
|
143
150
|
end
|
144
151
|
|
145
152
|
def is_admin_lookup(&blk)
|
146
|
-
|
147
|
-
@is_admin_lookup
|
153
|
+
configure(is_admin_lookup: blk) if blk
|
154
|
+
@config[:is_admin_lookup]
|
148
155
|
end
|
149
156
|
|
150
157
|
def extra_response_headers_lookup(&blk)
|
151
|
-
|
152
|
-
@extra_response_headers_lookup
|
158
|
+
configure(extra_response_headers_lookup: blk) if blk
|
159
|
+
@config[:extra_response_headers_lookup]
|
153
160
|
end
|
154
161
|
|
155
162
|
def on_connect(&blk)
|
156
|
-
|
157
|
-
@on_connect
|
163
|
+
configure(on_connect: blk) if blk
|
164
|
+
@config[:on_connect]
|
158
165
|
end
|
159
166
|
|
160
167
|
def on_disconnect(&blk)
|
161
|
-
|
162
|
-
@on_disconnect
|
168
|
+
configure(on_disconnect: blk) if blk
|
169
|
+
@config[:on_disconnect]
|
163
170
|
end
|
164
171
|
|
165
172
|
def allow_broadcast=(val)
|
166
|
-
|
173
|
+
configure(allow_broadcast: val)
|
167
174
|
end
|
168
175
|
|
169
176
|
def allow_broadcast?
|
170
|
-
@allow_broadcast ||=
|
177
|
+
@config[:allow_broadcast] ||=
|
171
178
|
if defined? ::Rails
|
172
179
|
::Rails.env.test? || ::Rails.env.development?
|
173
180
|
else
|
@@ -176,16 +183,24 @@ module MessageBus::Implementation
|
|
176
183
|
end
|
177
184
|
|
178
185
|
def reliable_pub_sub=(pub_sub)
|
179
|
-
|
186
|
+
configure(reliable_pub_sub: pub_sub)
|
180
187
|
end
|
181
188
|
|
182
189
|
def reliable_pub_sub
|
183
190
|
@mutex.synchronize do
|
184
191
|
return nil if @destroyed
|
185
|
-
@reliable_pub_sub ||=
|
192
|
+
@config[:reliable_pub_sub] ||= begin
|
193
|
+
@config[:backend_options] ||= {}
|
194
|
+
require "message_bus/backends/#{backend}"
|
195
|
+
MessageBus::BACKENDS[backend].new @config
|
196
|
+
end
|
186
197
|
end
|
187
198
|
end
|
188
199
|
|
200
|
+
def backend
|
201
|
+
@config[:backend] || :redis
|
202
|
+
end
|
203
|
+
|
189
204
|
def enable_diagnostics
|
190
205
|
MessageBus::Diagnostics.enable
|
191
206
|
end
|
@@ -333,11 +348,11 @@ module MessageBus::Implementation
|
|
333
348
|
# a keepalive will run every N seconds, if it fails
|
334
349
|
# process is killed
|
335
350
|
def keepalive_interval=(interval)
|
336
|
-
|
351
|
+
configure(keepalive_interval: interval)
|
337
352
|
end
|
338
353
|
|
339
354
|
def keepalive_interval
|
340
|
-
@keepalive_interval || 60
|
355
|
+
@config[:keepalive_interval] || 60
|
341
356
|
end
|
342
357
|
|
343
358
|
protected
|
@@ -459,6 +474,8 @@ module MessageBus::Implementation
|
|
459
474
|
|
460
475
|
@mutex.synchronize do
|
461
476
|
raise MessageBus::BusDestroyed if @destroyed
|
477
|
+
next unless @subscriptions
|
478
|
+
|
462
479
|
globals = @subscriptions[nil]
|
463
480
|
locals = @subscriptions[msg.site_id] if msg.site_id
|
464
481
|
|