message_bus 2.1.6 → 2.2.0.pre

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.

Potentially problematic release.


This version of message_bus might be problematic. Click here for more details.

Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +13 -92
  3. data/.rubocop_todo.yml +659 -0
  4. data/.travis.yml +1 -1
  5. data/CHANGELOG +61 -0
  6. data/Dockerfile +18 -0
  7. data/Gemfile +3 -1
  8. data/Guardfile +0 -1
  9. data/README.md +188 -101
  10. data/Rakefile +12 -1
  11. data/assets/message-bus.js +1 -1
  12. data/docker-compose.yml +46 -0
  13. data/examples/bench/config.ru +8 -9
  14. data/examples/bench/unicorn.conf.rb +1 -1
  15. data/examples/chat/chat.rb +150 -153
  16. data/examples/minimal/config.ru +2 -3
  17. data/lib/message_bus.rb +224 -36
  18. data/lib/message_bus/backends.rb +7 -0
  19. data/lib/message_bus/backends/base.rb +184 -0
  20. data/lib/message_bus/backends/memory.rb +304 -226
  21. data/lib/message_bus/backends/postgres.rb +359 -318
  22. data/lib/message_bus/backends/redis.rb +380 -337
  23. data/lib/message_bus/client.rb +99 -41
  24. data/lib/message_bus/connection_manager.rb +29 -21
  25. data/lib/message_bus/diagnostics.rb +50 -41
  26. data/lib/message_bus/distributed_cache.rb +5 -7
  27. data/lib/message_bus/message.rb +2 -2
  28. data/lib/message_bus/rack/diagnostics.rb +65 -55
  29. data/lib/message_bus/rack/middleware.rb +64 -44
  30. data/lib/message_bus/rack/thin_ext.rb +13 -9
  31. data/lib/message_bus/rails/railtie.rb +2 -0
  32. data/lib/message_bus/timer_thread.rb +2 -2
  33. data/lib/message_bus/version.rb +2 -1
  34. data/message_bus.gemspec +3 -2
  35. data/spec/assets/support/jasmine_helper.rb +1 -1
  36. data/spec/lib/fake_async_middleware.rb +1 -6
  37. data/spec/lib/message_bus/assets/asset_encoding_spec.rb +3 -3
  38. data/spec/lib/message_bus/backend_spec.rb +409 -0
  39. data/spec/lib/message_bus/client_spec.rb +8 -11
  40. data/spec/lib/message_bus/connection_manager_spec.rb +8 -14
  41. data/spec/lib/message_bus/distributed_cache_spec.rb +0 -4
  42. data/spec/lib/message_bus/multi_process_spec.rb +6 -7
  43. data/spec/lib/message_bus/rack/middleware_spec.rb +47 -43
  44. data/spec/lib/message_bus/timer_thread_spec.rb +0 -2
  45. data/spec/lib/message_bus_spec.rb +59 -43
  46. data/spec/spec_helper.rb +16 -4
  47. metadata +12 -9
  48. data/spec/lib/message_bus/backends/postgres_spec.rb +0 -221
  49. data/spec/lib/message_bus/backends/redis_spec.rb +0 -271
@@ -33,7 +33,6 @@ describe MessageBus::TimerThread do
33
33
  end
34
34
 
35
35
  it "queues jobs in the correct order" do
36
-
37
36
  results = []
38
37
  (0..3).to_a.reverse.each do |i|
39
38
  @timer.queue(0.005 * i) do
@@ -69,5 +68,4 @@ describe MessageBus::TimerThread do
69
68
 
70
69
  error.class.must_equal NameError
71
70
  end
72
-
73
71
  end
@@ -3,7 +3,6 @@ require 'message_bus'
3
3
  require 'redis'
4
4
 
5
5
  describe MessageBus do
6
-
7
6
  before do
8
7
  @bus = MessageBus::Instance.new
9
8
  @bus.site_id_lookup do
@@ -17,6 +16,25 @@ describe MessageBus do
17
16
  @bus.destroy
18
17
  end
19
18
 
19
+ it "can be turned off" do
20
+ @bus.off
21
+
22
+ @bus.off?.must_equal true
23
+ end
24
+
25
+ it "can call destroy twice" do
26
+ @bus.destroy
27
+ @bus.destroy
28
+ end
29
+
30
+ it "can be turned on after destroy" do
31
+ @bus.destroy
32
+
33
+ @bus.on
34
+
35
+ @bus.after_fork
36
+ end
37
+
20
38
  it "can subscribe from a point in time" do
21
39
  @bus.publish("/minion", "banana")
22
40
 
@@ -59,11 +77,9 @@ describe MessageBus do
59
77
  wait_for(2000) { client_ids }
60
78
 
61
79
  client_ids.must_equal ['a', 'b']
62
-
63
80
  end
64
81
 
65
82
  it "should recover from a redis flush" do
66
-
67
83
  data = nil
68
84
  @bus.subscribe("/chuck") do |msg|
69
85
  data = msg.data
@@ -79,7 +95,24 @@ describe MessageBus do
79
95
  wait_for(2000) { data && data["yeager"] }
80
96
 
81
97
  data["yeager"].must_equal true
98
+ end
99
+
100
+ it "should recover from a backlog expiring" do
101
+ data = nil
102
+ @bus.subscribe("/chuck") do |msg|
103
+ data = msg.data
104
+ end
105
+ @bus.publish("/chuck", norris: true)
106
+ @bus.publish("/chuck", norris: true)
107
+ @bus.publish("/chuck", norris: true)
82
108
 
109
+ @bus.reliable_pub_sub.expire_all_backlogs!
110
+
111
+ @bus.publish("/chuck", yeager: true)
112
+
113
+ wait_for(2000) { data && data["yeager"] }
114
+
115
+ data["yeager"].must_equal true
83
116
  end
84
117
 
85
118
  it "should automatically decode hashed messages" do
@@ -111,7 +144,6 @@ describe MessageBus do
111
144
  site_id.must_equal 'magic'
112
145
  channel.must_equal '/chuck'
113
146
  user_ids.must_equal [1, 2, 3]
114
-
115
147
  end
116
148
 
117
149
  it "should get global messages if it subscribes to them" do
@@ -130,7 +162,6 @@ describe MessageBus do
130
162
  data.must_equal 'norris'
131
163
  site_id.must_equal 'magic'
132
164
  channel.must_equal '/chuck'
133
-
134
165
  end
135
166
 
136
167
  it "should have the ability to grab the backlog messages in the correct order" do
@@ -149,7 +180,6 @@ describe MessageBus do
149
180
  @bus.publish("/chuckles", "bar")
150
181
 
151
182
  @bus.backlog("/chuck").map { |i| i.data }.to_a.must_equal ['norris', 'foo']
152
-
153
183
  end
154
184
 
155
185
  it "allows you to look up last_message" do
@@ -193,7 +223,6 @@ describe MessageBus do
193
223
  end
194
224
 
195
225
  it "can subscribe globally" do
196
-
197
226
  data = nil
198
227
  @bus.subscribe do |message|
199
228
  data = message.data
@@ -206,7 +235,6 @@ describe MessageBus do
206
235
  end
207
236
 
208
237
  it "can subscribe to channel" do
209
-
210
238
  data = nil
211
239
  @bus.subscribe("/global/test") do |message|
212
240
  data = message.data
@@ -229,49 +257,37 @@ describe MessageBus do
229
257
  @bus.publish("/global/test", "test", user_ids: [1])
230
258
  end.must_raise(MessageBus::InvalidMessage)
231
259
  end
232
-
233
260
  end
234
261
 
235
- unless MESSAGE_BUS_CONFIG[:backend] == :memory
236
- it "should support forking properly do" do
237
- data = []
238
- @bus.subscribe do |msg|
239
- data << msg.data
240
- end
241
-
242
- @bus.publish("/hello", "world")
243
- wait_for(2000) { data.length > 0 }
244
-
245
- if child = Process.fork
246
-
247
- wait_for(2000) { data.include?("ready") }
248
- data.must_include "ready"
249
-
250
- @bus.publish("/hello", "world1")
262
+ it "should support forking properly do" do
263
+ test_never :memory
251
264
 
252
- wait_for(2000) { data.include?("got it") }
253
- data.must_include "got it"
254
- Process.wait(child)
255
-
256
- else
257
- begin
258
- @bus.after_fork
259
- @bus.publish("/hello", "ready")
265
+ data = []
266
+ @bus.subscribe do |msg|
267
+ data << msg.data
268
+ end
260
269
 
261
- wait_for(2000) { data.include? "world1" }
270
+ @bus.publish("/hello", "pre-fork")
271
+ wait_for(2000) { data.length > 0 }
262
272
 
263
- if (data.include? "world1")
264
- @bus.publish("/hello", "got it")
265
- end
273
+ if child = Process.fork
274
+ # The child was forked and we received its PID
266
275
 
267
- $stdout.reopen("/dev/null", "w")
268
- $stderr.reopen("/dev/null", "w")
276
+ # Wait for fork to finish so we're asserting that we can still publish after it has
277
+ Process.wait(child)
269
278
 
270
- ensure
271
- exit!(0)
272
- end
279
+ @bus.publish("/hello", "continuation")
280
+ else
281
+ begin
282
+ @bus.after_fork
283
+ @bus.publish("/hello", "from-fork")
284
+ ensure
285
+ exit!(0)
273
286
  end
274
-
275
287
  end
288
+
289
+ wait_for(2000) { data.length == 3 }
290
+
291
+ data.must_equal(["pre-fork", "from-fork", "continuation"])
276
292
  end
277
293
  end
@@ -8,15 +8,18 @@ require 'minitest/autorun'
8
8
  require 'minitest/spec'
9
9
 
10
10
  backend = (ENV['MESSAGE_BUS_BACKEND'] || :redis).to_sym
11
- MESSAGE_BUS_CONFIG = {:backend=>backend}
11
+ MESSAGE_BUS_CONFIG = { backend: backend }
12
12
  require "message_bus/backends/#{backend}"
13
13
  PUB_SUB_CLASS = MessageBus::BACKENDS.fetch(backend)
14
- if backend == :postgres
15
- MESSAGE_BUS_CONFIG.merge!(:backend_options=>{:user=>ENV['PGUSER'] || ENV['USER'], :dbname=>ENV['PGDATABASE'] || 'message_bus_test'})
14
+ case backend
15
+ when :redis
16
+ MESSAGE_BUS_CONFIG.merge!(url: ENV['REDISURL'])
17
+ when :postgres
18
+ MESSAGE_BUS_CONFIG.merge!(backend_options: { host: ENV['PGHOST'], user: ENV['PGUSER'] || ENV['USER'], password: ENV['PGPASSWORD'], dbname: ENV['PGDATABASE'] || 'message_bus_test' })
16
19
  end
17
20
  puts "Running with backend: #{backend}"
18
21
 
19
- def wait_for(timeout_milliseconds=2000)
22
+ def wait_for(timeout_milliseconds = 2000)
20
23
  timeout = (timeout_milliseconds + 0.0) / 1000
21
24
  finish = Time.now + timeout
22
25
 
@@ -25,5 +28,14 @@ def wait_for(timeout_milliseconds=2000)
25
28
  sleep(0.001)
26
29
  end
27
30
  end.join
31
+ end
32
+
33
+ def test_only(*backends)
34
+ backend = MESSAGE_BUS_CONFIG[:backend]
35
+ skip "Test doesn't apply to #{backend}" unless backends.include?(backend)
36
+ end
28
37
 
38
+ def test_never(*backends)
39
+ backend = MESSAGE_BUS_CONFIG[:backend]
40
+ skip "Test doesn't apply to #{backend}" if backends.include?(backend)
29
41
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: message_bus
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.6
4
+ version: 2.2.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-15 00:00:00.000000000 Z
11
+ date: 2018-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -61,8 +61,10 @@ extra_rdoc_files: []
61
61
  files:
62
62
  - ".gitignore"
63
63
  - ".rubocop.yml"
64
+ - ".rubocop_todo.yml"
64
65
  - ".travis.yml"
65
66
  - CHANGELOG
67
+ - Dockerfile
66
68
  - Gemfile
67
69
  - Guardfile
68
70
  - LICENSE
@@ -76,6 +78,7 @@ files:
76
78
  - assets/jquery-1.8.2.js
77
79
  - assets/message-bus-ajax.js
78
80
  - assets/message-bus.js
81
+ - docker-compose.yml
79
82
  - examples/bench/bench.lua
80
83
  - examples/bench/config.ru
81
84
  - examples/bench/puma.rb
@@ -89,6 +92,8 @@ files:
89
92
  - examples/minimal/Gemfile
90
93
  - examples/minimal/config.ru
91
94
  - lib/message_bus.rb
95
+ - lib/message_bus/backends.rb
96
+ - lib/message_bus/backends/base.rb
92
97
  - lib/message_bus/backends/memory.rb
93
98
  - lib/message_bus/backends/postgres.rb
94
99
  - lib/message_bus/backends/redis.rb
@@ -111,8 +116,7 @@ files:
111
116
  - spec/assets/support/jasmine_helper.rb
112
117
  - spec/lib/fake_async_middleware.rb
113
118
  - spec/lib/message_bus/assets/asset_encoding_spec.rb
114
- - spec/lib/message_bus/backends/postgres_spec.rb
115
- - spec/lib/message_bus/backends/redis_spec.rb
119
+ - spec/lib/message_bus/backend_spec.rb
116
120
  - spec/lib/message_bus/client_spec.rb
117
121
  - spec/lib/message_bus/connection_manager_spec.rb
118
122
  - spec/lib/message_bus/distributed_cache_spec.rb
@@ -136,12 +140,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
136
140
  requirements:
137
141
  - - ">="
138
142
  - !ruby/object:Gem::Version
139
- version: 2.2.0
143
+ version: 2.3.0
140
144
  required_rubygems_version: !ruby/object:Gem::Requirement
141
145
  requirements:
142
- - - ">="
146
+ - - ">"
143
147
  - !ruby/object:Gem::Version
144
- version: '0'
148
+ version: 1.3.1
145
149
  requirements: []
146
150
  rubyforge_project:
147
151
  rubygems_version: 2.7.6
@@ -155,8 +159,7 @@ test_files:
155
159
  - spec/assets/support/jasmine_helper.rb
156
160
  - spec/lib/fake_async_middleware.rb
157
161
  - spec/lib/message_bus/assets/asset_encoding_spec.rb
158
- - spec/lib/message_bus/backends/postgres_spec.rb
159
- - spec/lib/message_bus/backends/redis_spec.rb
162
+ - spec/lib/message_bus/backend_spec.rb
160
163
  - spec/lib/message_bus/client_spec.rb
161
164
  - spec/lib/message_bus/connection_manager_spec.rb
162
165
  - spec/lib/message_bus/distributed_cache_spec.rb
@@ -1,221 +0,0 @@
1
- require_relative '../../../spec_helper'
2
- require 'message_bus'
3
-
4
- if MESSAGE_BUS_CONFIG[:backend] == :postgres || MESSAGE_BUS_CONFIG[:backend] == :memory
5
- describe PUB_SUB_CLASS do
6
-
7
- def new_test_bus
8
- PUB_SUB_CLASS.new(MESSAGE_BUS_CONFIG.merge(:db => 10))
9
- end
10
-
11
- before do
12
- @bus = new_test_bus
13
- @bus.reset!
14
- end
15
-
16
- describe "readonly" do
17
-
18
- after do
19
- @bus.pub_redis.slaveof "no", "one"
20
- end
21
-
22
- it "should be able to store messages in memory for a period while in read only" do
23
-
24
- skip "This spec changes redis behavior that in turn means other specs run slow"
25
-
26
- @bus.pub_redis.slaveof "127.0.0.80", "666"
27
- @bus.max_in_memory_publish_backlog = 2
28
-
29
- 3.times do
30
- result = @bus.publish "/foo", "bar"
31
- assert_nil result
32
- end
33
-
34
- @bus.pub_redis.slaveof "no", "one"
35
- sleep 0.01
36
-
37
- @bus.backlog("/foo", 0).map(&:data).must_equal ["bar","bar"]
38
-
39
- end
40
- end
41
-
42
- it "should be able to access the backlog" do
43
- @bus.publish "/foo", "bar"
44
- @bus.publish "/foo", "baz"
45
-
46
- @bus.backlog("/foo", 0).to_a.must_equal [
47
- MessageBus::Message.new(1,1,'/foo','bar'),
48
- MessageBus::Message.new(2,2,'/foo','baz')
49
- ]
50
- end
51
-
52
- it "should initialize with max_backlog_size" do
53
- PUB_SUB_CLASS.new({},2000).max_backlog_size.must_equal 2000
54
- end
55
-
56
- it "should truncate channels correctly" do
57
- @bus.max_backlog_size = 2
58
- 4.times do |t|
59
- @bus.publish "/foo", "1#{t}"
60
- end
61
-
62
- @bus.backlog("/foo").to_a.must_equal [
63
- MessageBus::Message.new(3,3,'/foo','12'),
64
- MessageBus::Message.new(4,4,'/foo','13'),
65
- ]
66
- end
67
-
68
- it "should truncate global backlog correctly" do
69
- @bus.max_global_backlog_size = 2
70
- @bus.publish "/foo", "11"
71
- @bus.publish "/bar", "21"
72
- @bus.publish "/baz", "31"
73
-
74
- @bus.global_backlog.length.must_equal 2
75
- end
76
-
77
- it "should support clear_every setting" do
78
- @bus.clear_every = 5
79
- @bus.max_global_backlog_size = 2
80
- @bus.publish "/foo", "11"
81
- @bus.publish "/bar", "21"
82
- @bus.publish "/baz", "31"
83
- @bus.publish "/bar", "41"
84
- @bus.global_backlog.length.must_equal 4
85
-
86
- @bus.publish "/baz", "51"
87
- @bus.global_backlog.length.must_equal 2
88
- end
89
-
90
- it "should be able to grab a message by id" do
91
- id1 = @bus.publish "/foo", "bar"
92
- id2 = @bus.publish "/foo", "baz"
93
- @bus.get_message("/foo", id2).must_equal MessageBus::Message.new(2, 2, "/foo", "baz")
94
- @bus.get_message("/foo", id1).must_equal MessageBus::Message.new(1, 1, "/foo", "bar")
95
- end
96
-
97
- it "should be able to access the global backlog" do
98
- @bus.publish "/foo", "bar"
99
- @bus.publish "/hello", "world"
100
- @bus.publish "/foo", "baz"
101
- @bus.publish "/hello", "planet"
102
-
103
- @bus.global_backlog.to_a.must_equal [
104
- MessageBus::Message.new(1, 1, "/foo", "bar"),
105
- MessageBus::Message.new(2, 2, "/hello", "world"),
106
- MessageBus::Message.new(3, 3, "/foo", "baz"),
107
- MessageBus::Message.new(4, 4, "/hello", "planet")
108
- ]
109
- end
110
-
111
- it "should correctly omit dropped messages from the global backlog" do
112
- @bus.max_backlog_size = 1
113
- @bus.publish "/foo", "a1"
114
- @bus.publish "/foo", "b1"
115
- @bus.publish "/bar", "a1"
116
- @bus.publish "/bar", "b1"
117
-
118
- @bus.global_backlog.to_a.must_equal [
119
- MessageBus::Message.new(2, 2, "/foo", "b1"),
120
- MessageBus::Message.new(4, 4, "/bar", "b1")
121
- ]
122
- end
123
-
124
- it "should have the correct number of messages for multi threaded access" do
125
- threads = []
126
- 4.times do
127
- threads << Thread.new do
128
- bus = @bus
129
- 25.times {
130
- bus.publish "/foo", ".."
131
- }
132
- end
133
- end
134
-
135
- threads.each{|t| t.join}
136
- @bus.backlog("/foo").length == 100
137
- end
138
-
139
- it "should be able to subscribe globally with recovery" do
140
- @bus.publish("/foo", "11")
141
- @bus.publish("/bar", "12")
142
- got = []
143
-
144
- t = Thread.new do
145
- @bus.global_subscribe(0) do |msg|
146
- got << msg
147
- end
148
- end
149
-
150
- @bus.publish("/bar", "13")
151
-
152
- wait_for(100) do
153
- got.length == 3
154
- end
155
-
156
- t.kill
157
-
158
- got.length.must_equal 3
159
- got.map{|m| m.data}.must_equal ["11","12","13"]
160
- end
161
-
162
- it "should be able to encode and decode messages properly" do
163
- m = MessageBus::Message.new 1,2,'||','||'
164
- MessageBus::Message.decode(m.encode).must_equal m
165
- end
166
-
167
- it "should handle subscribe on single channel, with recovery" do
168
- @bus.publish("/foo", "11")
169
- @bus.publish("/bar", "12")
170
- got = []
171
-
172
- t = Thread.new do
173
- @bus.subscribe("/foo",0) do |msg|
174
- got << msg
175
- end
176
- end
177
-
178
- @bus.publish("/foo", "13")
179
-
180
- wait_for(100) do
181
- got.length == 2
182
- end
183
-
184
- t.kill
185
-
186
- got.map{|m| m.data}.must_equal ["11","13"]
187
- end
188
-
189
- it "should not get backlog if subscribe is called without params" do
190
- @bus.publish("/foo", "11")
191
- got = []
192
-
193
- t = Thread.new do
194
- @bus.subscribe("/foo") do |msg|
195
- got << msg
196
- end
197
- end
198
-
199
- # sleep 50ms to allow the bus to correctly subscribe,
200
- # I thought about adding a subscribed callback, but outside of testing it matters less
201
- sleep 0.05
202
-
203
- @bus.publish("/foo", "12")
204
-
205
- wait_for(100) do
206
- got.length == 1
207
- end
208
-
209
- t.kill
210
-
211
- got.map{|m| m.data}.must_equal ["12"]
212
- end
213
-
214
- it "should allow us to get last id on a channel" do
215
- @bus.last_id("/foo").must_equal 0
216
- @bus.publish("/foo", "11")
217
- @bus.last_id("/foo").must_equal 1
218
- end
219
-
220
- end
221
- end