message_bus 2.1.6 → 2.2.0.pre

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.

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