message_bus 2.0.2 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 80297cfac62f4fc79e8d16a425762576757aab5d
4
- data.tar.gz: be8b74aed2b678c858de6a2941f74bcbaad455c2
3
+ metadata.gz: f3cdd346c2878cd29ee74ec652ad39b524322db2
4
+ data.tar.gz: dcb547c36393e89b014e61eb37fa01757a813fac
5
5
  SHA512:
6
- metadata.gz: 32fafd6d57c0176cc356724246909d430753428b375449b8c12a181dd8b2f50ab51404a6fd0c02a089cc7fbe2bf90e6071df6b5a24324fa0b0430e3c6f163460
7
- data.tar.gz: e977e8bc61bdd4c74be64fe755ad413e036ae96fc149ccb26cbae05fb1bca53dcb45cf82b0ea6ae5e77e13ee3e3fc7a87a5068d6cbe98e5994f440c9668e43ca
6
+ metadata.gz: ad0c582fa78e53d1d59d355ee595b05e3d74ffb68858a3617db6fcbab45005220566e2baf74b9ea57bb19b3f03ccdc222928cf3b4e91dfe8f6cf015059b0fe67
7
+ data.tar.gz: faf5a01c159e6b016e7d99f418b195330ea3382390a306eef54be053b69d85b4bcf413ee4fa68d1dcf5f79a812822ac804ae38cc0d54bd0d1eb367c9182eb1bc
data/.rubocop.yml ADDED
@@ -0,0 +1,104 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.4
3
+ DisabledByDefault: true
4
+
5
+ # Prefer &&/|| over and/or.
6
+ Style/AndOr:
7
+ Enabled: true
8
+
9
+ # Do not use braces for hash literals when they are the last argument of a
10
+ # method call.
11
+ Style/BracesAroundHashParameters:
12
+ Enabled: true
13
+
14
+ # Align `when` with `case`.
15
+ Layout/CaseIndentation:
16
+ Enabled: true
17
+
18
+ # Align comments with method definitions.
19
+ Layout/CommentIndentation:
20
+ Enabled: true
21
+
22
+ # No extra empty lines.
23
+ Layout/EmptyLines:
24
+ Enabled: true
25
+
26
+ # Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
27
+ Style/HashSyntax:
28
+ Enabled: true
29
+
30
+ # Two spaces, no tabs (for indentation).
31
+ Layout/IndentationWidth:
32
+ Enabled: true
33
+
34
+ Layout/SpaceAfterColon:
35
+ Enabled: true
36
+
37
+ Layout/SpaceAfterComma:
38
+ Enabled: true
39
+
40
+ Layout/SpaceAroundEqualsInParameterDefault:
41
+ Enabled: true
42
+
43
+ Layout/SpaceAroundKeyword:
44
+ Enabled: true
45
+
46
+ Layout/SpaceAroundOperators:
47
+ Enabled: true
48
+
49
+ Layout/SpaceBeforeFirstArg:
50
+ Enabled: true
51
+
52
+ # Defining a method with parameters needs parentheses.
53
+ Style/MethodDefParentheses:
54
+ Enabled: true
55
+
56
+ # Use `foo {}` not `foo{}`.
57
+ Layout/SpaceBeforeBlockBraces:
58
+ Enabled: true
59
+
60
+ # Use `foo { bar }` not `foo {bar}`.
61
+ Layout/SpaceInsideBlockBraces:
62
+ Enabled: true
63
+
64
+ # Use `{ a: 1 }` not `{a:1}`.
65
+ Layout/SpaceInsideHashLiteralBraces:
66
+ Enabled: true
67
+
68
+ Layout/SpaceInsideParens:
69
+ Enabled: true
70
+
71
+ # Detect hard tabs, no hard tabs.
72
+ Layout/Tab:
73
+ Enabled: true
74
+
75
+ # Blank lines should not have any spaces.
76
+ Layout/TrailingBlankLines:
77
+ Enabled: true
78
+
79
+ # No trailing whitespace.
80
+ Layout/TrailingWhitespace:
81
+ Enabled: true
82
+
83
+ Lint/BlockAlignment:
84
+ Enabled: true
85
+
86
+ # Align `end` with the matching keyword or starting expression except for
87
+ # assignments, where it should be aligned with the LHS.
88
+ Lint/EndAlignment:
89
+ Enabled: true
90
+ EnforcedStyleAlignWith: variable
91
+
92
+ # Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
93
+ Lint/RequireParentheses:
94
+ Enabled: true
95
+
96
+ Layout/MultilineMethodCallIndentation:
97
+ Enabled: true
98
+ EnforcedStyle: indented
99
+
100
+ Layout/AlignHash:
101
+ Enabled: true
102
+
103
+ Bundler/OrderedGems:
104
+ Enabled: false
data/CHANGELOG CHANGED
@@ -1,3 +1,12 @@
1
+ 16-08-2017
2
+
3
+ - Version 2.0.3
4
+ - Fix: broken MessageBus.redis_config
5
+ - Perf: publish status message for filtered messages
6
+ - Perf: add frozen strings to save on memory
7
+ - Feature: improved logging when messages are dropped
8
+ - Fix: handle missing actiondispatch flash
9
+
1
10
  25-08-2016
2
11
 
3
12
  - Version 2.0.2
data/README.md CHANGED
@@ -14,6 +14,18 @@ Live chat demo per [examples/chat](https://github.com/SamSaffron/message_bus/tre
14
14
 
15
15
  ### http://chat.samsaffron.com
16
16
 
17
+
18
+ ## Want to help?
19
+
20
+ If you are looking to contribute to this project here are some ideas
21
+
22
+ - Build backends for other providers (zeromq, rabbitmq, disque) - currently we support pg and redis.
23
+ - Improve and properly document admin dashboard (add opt-in stats, better diagnostics into queues)
24
+ - Improve general documentation (Add examples, refine existing examples)
25
+ - Make MessageBus a nice website
26
+ - Add optional transports for websocket and shared web workers
27
+ - Add `# frozen_string_literal: true` to all non test files and adjust code to allow for it.
28
+
17
29
  ## Can you handle concurrent requests?
18
30
 
19
31
  **Yes**, MessageBus uses Rack Hijack, this interface allows us to take control of the underlying socket. MessageBus can handle thousands of concurrent long polls on all popular Ruby webservers. MessageBus runs as middleware in your Rack (or by extension Rails) application and does not require a dedicated server. Background work is minimized to ensure it does not interfere with existing non MessageBus traffic.
@@ -71,10 +83,10 @@ MessageBus.publish "/channel", "hello", client_ids: ["XXX","YYY"]
71
83
  # message bus determines the user ids and groups based on env
72
84
 
73
85
  MessageBus.configure(user_id_lookup: proc do |env|
74
- # this lookup occurs on JS-client poolings, so that server can retrieve backlog
86
+ # this lookup occurs on JS-client poolings, so that server can retrieve backlog
75
87
  # for the client considering/matching/filtering user_ids set on published messages
76
88
  # if user_id is not set on publish time, any user_id returned here will receive the message
77
-
89
+
78
90
  # return the user id here
79
91
  end)
80
92
 
@@ -200,7 +212,7 @@ Setting|Default|Info
200
212
  ----|---|---|
201
213
  enableLongPolling|true|Allow long-polling (provided it is enable by the server)
202
214
  callbackInterval|15000|Safeguard to ensure background polling does not exceed this interval (in milliseconds)
203
- backgroundCallbackInterval|60000|Interval to poll when long polling is disabled (either explicitly or due to browser being in backgroud)
215
+ backgroundCallbackInterval|60000|Interval to poll when long polling is disabled (either explicitly or due to browser being in background)
204
216
  maxPollInterval|180000|If request to the server start failing, MessageBus will backoff, this is the upper limit of the backoff.
205
217
  alwaysLongPoll|false|For debugging you may want to disable the "is browser in background" check and always long-poll
206
218
  baseUrl|/|If message bus is mounted in a subdirectory of different domain, you may configure it to perform requests there
@@ -322,14 +334,53 @@ after_fork do |server, worker|
322
334
  end
323
335
  ```
324
336
 
325
- ###
337
+ ### Middleware stack in Rails
326
338
 
327
- ## Want to help?
339
+ MessageBus middleware has to show up after the session middleware, but depending on how the Rails app is configured that might be either `ActionDispatch::Session::CookieStore` or `ActionDispatch::Session::ActiveRecordStore`. To handle both cases, the middleware is inserted before `ActionDispatch::Flash`.
340
+
341
+ For APIs or apps that have `ActionDispatch::Flash` deleted from the stack the middleware is pushed to the bottom.
342
+
343
+ Should you want to manipulate the default behavior please refer to [Rails MiddlewareStackProxy documentation](http://api.rubyonrails.org/classes/Rails/Configuration/MiddlewareStackProxy.html) and alter the order of the middlewares in stack in `app/config/initializers/message_bus.rb`
344
+
345
+ ```ruby
346
+ # config/initializers/message_bus.rb
347
+ Rails.application.config do |config|
348
+ # do anything you wish with config.middleware here
349
+ end
350
+ ```
351
+
352
+ #### Error Handling
353
+
354
+ The internet is a chaotic environment and clients can drop off for a variety of reasons. If this happens while MessageBus is trying to write a message to the client you may see something like this in your logs:
355
+
356
+ ```
357
+ Errno::EPIPE: Broken pipe
358
+ from message_bus/client.rb:159:in `write'
359
+ from message_bus/client.rb:159:in `write_headers'
360
+ from message_bus/client.rb:178:in `write_chunk'
361
+ from message_bus/client.rb:49:in `ensure_first_chunk_sent'
362
+ from message_bus/rack/middleware.rb:150:in `block in call'
363
+ from message_bus/client.rb:21:in `block in synchronize'
364
+ from message_bus/client.rb:21:in `synchronize'
365
+ from message_bus/client.rb:21:in `synchronize'
366
+ from message_bus/rack/middleware.rb:147:in `call'
367
+ ...
368
+ ```
369
+
370
+ The user doesn't see anything, but depending on your traffic you may acquire quite a few of these in your logs.
371
+
372
+ You can rescue from errors that occur in MessageBus's middleware stack by adding a config option:
373
+
374
+ ```ruby
375
+ MessageBus.configure(on_middleware_error: proc do |env, e|
376
+ # env contains the Rack environment at the time of error
377
+ # e contains the exception that was raised
378
+ if Errno::EPIPE === e
379
+ [422, {}, [""]]
380
+ else
381
+ raise e
382
+ end
383
+ end)
384
+ ```
328
385
 
329
- If you are looking to contribute to this project here are some ideas
330
386
 
331
- - Add a test suite for JavaScript message-bus.js
332
- - Build backends for other providers (zeromq, rabbitmq, disque)
333
- - Improve and properly document admin dashboard (add opt-in stats, better diagnostics into queues)
334
- - Improve general documentation (Add examples, refine existing examples)
335
- - Make MessageBus a nice website
data/lib/message_bus.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "monitor"
2
3
  require "set"
3
4
  require "message_bus/version"
@@ -129,7 +130,7 @@ module MessageBus::Implementation
129
130
 
130
131
  # Allow us to inject a redis db
131
132
  def redis_config=(config)
132
- configure(config.merge(:backend=>:redis))
133
+ configure(config.merge(backend: :redis))
133
134
  end
134
135
 
135
136
  alias redis_config config
@@ -228,17 +229,17 @@ module MessageBus::Implementation
228
229
 
229
230
  raise ::MessageBus::InvalidMessage if (user_ids || group_ids) && global?(channel)
230
231
 
231
- encoded_data = JSON.dump({
232
+ encoded_data = JSON.dump(
232
233
  data: data,
233
234
  user_ids: user_ids,
234
235
  group_ids: group_ids,
235
236
  client_ids: client_ids
236
- })
237
+ )
237
238
 
238
239
  reliable_pub_sub.publish(encode_channel_name(channel), encoded_data)
239
240
  end
240
241
 
241
- def blocking_subscribe(channel=nil, &blk)
242
+ def blocking_subscribe(channel = nil, &blk)
242
243
  if channel
243
244
  reliable_pub_sub.subscribe(encode_channel_name(channel), &blk)
244
245
  else
@@ -249,7 +250,7 @@ module MessageBus::Implementation
249
250
  ENCODE_SITE_TOKEN = "$|$"
250
251
 
251
252
  # encode channel name to include site
252
- def encode_channel_name(channel, site_id=nil)
253
+ def encode_channel_name(channel, site_id = nil)
253
254
  if (site_id || site_id_lookup) && !global?(channel)
254
255
  raise ArgumentError.new channel if channel.include? ENCODE_SITE_TOKEN
255
256
  "#{channel}#{ENCODE_SITE_TOKEN}#{site_id || site_id_lookup.call}"
@@ -262,50 +263,50 @@ module MessageBus::Implementation
262
263
  channel.split(ENCODE_SITE_TOKEN)
263
264
  end
264
265
 
265
- def subscribe(channel=nil, last_id=-1, &blk)
266
+ def subscribe(channel = nil, last_id = -1, &blk)
266
267
  subscribe_impl(channel, nil, last_id, &blk)
267
268
  end
268
269
 
269
270
  # subscribe only on current site
270
- def local_subscribe(channel=nil, last_id=-1, &blk)
271
+ def local_subscribe(channel = nil, last_id = -1, &blk)
271
272
  site_id = site_id_lookup.call if site_id_lookup && ! global?(channel)
272
273
  subscribe_impl(channel, site_id, last_id, &blk)
273
274
  end
274
275
 
275
- def unsubscribe(channel=nil, &blk)
276
+ def unsubscribe(channel = nil, &blk)
276
277
  unsubscribe_impl(channel, nil, &blk)
277
278
  end
278
279
 
279
- def local_unsubscribe(channel=nil, &blk)
280
+ def local_unsubscribe(channel = nil, &blk)
280
281
  site_id = site_id_lookup.call if site_id_lookup
281
282
  unsubscribe_impl(channel, site_id, &blk)
282
283
  end
283
284
 
284
- def global_backlog(last_id=nil)
285
+ def global_backlog(last_id = nil)
285
286
  backlog(nil, last_id)
286
287
  end
287
288
 
288
- def backlog(channel=nil, last_id=nil, site_id=nil)
289
+ def backlog(channel = nil, last_id = nil, site_id = nil)
289
290
  old =
290
291
  if channel
291
- reliable_pub_sub.backlog(encode_channel_name(channel,site_id), last_id)
292
+ reliable_pub_sub.backlog(encode_channel_name(channel, site_id), last_id)
292
293
  else
293
294
  reliable_pub_sub.global_backlog(last_id)
294
295
  end
295
296
 
296
- old.each{ |m|
297
+ old.each do |m|
297
298
  decode_message!(m)
298
- }
299
+ end
299
300
  old
300
301
  end
301
302
 
302
- def last_id(channel,site_id=nil)
303
- reliable_pub_sub.last_id(encode_channel_name(channel,site_id))
303
+ def last_id(channel , site_id = nil)
304
+ reliable_pub_sub.last_id(encode_channel_name(channel, site_id))
304
305
  end
305
306
 
306
307
  def last_message(channel)
307
308
  if last_id = last_id(channel)
308
- messages = backlog(channel, last_id-1)
309
+ messages = backlog(channel, last_id - 1)
309
310
  if messages
310
311
  messages[0]
311
312
  end
@@ -326,7 +327,7 @@ module MessageBus::Implementation
326
327
  reliable_pub_sub.after_fork
327
328
  ensure_subscriber_thread
328
329
  # will ensure timer is running
329
- timer.queue{}
330
+ timer.queue {}
330
331
  end
331
332
 
332
333
  def listening?
@@ -403,7 +404,7 @@ module MessageBus::Implementation
403
404
  if just_yield
404
405
  original_blk.call m
405
406
  else
406
- if current_id && current_id == (m.message_id-1)
407
+ if current_id && current_id == (m.message_id - 1)
407
408
  original_blk.call m
408
409
  just_yield = true
409
410
  else
@@ -418,14 +419,14 @@ module MessageBus::Implementation
418
419
 
419
420
  @subscriptions ||= {}
420
421
  @subscriptions[site_id] ||= {}
421
- @subscriptions[site_id][channel] ||= []
422
+ @subscriptions[site_id][channel] ||= []
422
423
  @subscriptions[site_id][channel] << blk
423
424
  ensure_subscriber_thread
424
425
 
425
426
  attempts = 100
426
427
  while attempts > 0 && !reliable_pub_sub.subscribed
427
428
  sleep 0.001
428
- attempts-=1
429
+ attempts -= 1
429
430
  end
430
431
 
431
432
  raise MessageBus::BusDestroyed if @destroyed
@@ -444,7 +445,6 @@ module MessageBus::Implementation
444
445
 
445
446
  end
446
447
 
447
-
448
448
  def ensure_subscriber_thread
449
449
  @mutex.synchronize do
450
450
  return if (@subscriber_thread && @subscriber_thread.alive?) || @destroyed
@@ -473,7 +473,7 @@ module MessageBus::Implementation
473
473
  publish("/__mb_keepalive__/", Process.pid, user_ids: [-1])
474
474
  # going for x3 keepalives missed for a restart, need to ensure this only very rarely happens
475
475
  # note: after_fork will sort out a bad @last_message date, but thread will be dead anyway
476
- if (Time.now - (@last_message || Time.now)) > keepalive_interval*3
476
+ if (Time.now - (@last_message || Time.now)) > keepalive_interval * 3
477
477
  MessageBus.logger.warn "Global messages on #{Process.pid} timed out, restarting process"
478
478
  # No other clean way to remove this thread, its listening on a socket
479
479
  # no data is arriving
@@ -530,7 +530,7 @@ module MessageBus::Implementation
530
530
  locals = locals[msg.channel] if locals
531
531
  end
532
532
 
533
- multi_each(globals,locals, global_globals, local_globals) do |c|
533
+ multi_each(globals, locals, global_globals, local_globals) do |c|
534
534
  begin
535
535
  c.call msg
536
536
  rescue => e
@@ -544,7 +544,7 @@ module MessageBus::Implementation
544
544
  end
545
545
  end
546
546
 
547
- def multi_each(*args,&block)
547
+ def multi_each(*args, &block)
548
548
  args.each do |a|
549
549
  a.each(&block) if a
550
550
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module MessageBus::Memory; end
2
3
 
3
4
  class MessageBus::Memory::Client
@@ -33,7 +34,7 @@ class MessageBus::Memory::Client
33
34
  end
34
35
  msg = MessageBus::Message.new id, id, channel, value
35
36
  payload = msg.encode
36
- listeners.each{|l| l.push(payload)}
37
+ listeners.each { |l| l.push(payload) }
37
38
  id
38
39
  end
39
40
 
@@ -42,7 +43,7 @@ class MessageBus::Memory::Client
42
43
  oldest = backlog_id - num_to_keep
43
44
  sync do
44
45
  @channels.each_value do |entries|
45
- entries.delete_if{|id, _| id <= oldest}
46
+ entries.delete_if { |id, _| id <= oldest }
46
47
  end
47
48
  end
48
49
  nil
@@ -51,24 +52,24 @@ class MessageBus::Memory::Client
51
52
 
52
53
  def clear_channel_backlog(channel, backlog_id, num_to_keep)
53
54
  oldest = backlog_id - num_to_keep
54
- sync{chan(channel).delete_if{|id, _| id <= oldest}}
55
+ sync { chan(channel).delete_if { |id, _| id <= oldest } }
55
56
  nil
56
57
  end
57
58
 
58
59
  def backlog(channel, backlog_id)
59
- sync{chan(channel).select{|id, _| id > backlog_id}}
60
+ sync { chan(channel).select { |id, _| id > backlog_id } }
60
61
  end
61
62
 
62
63
  def global_backlog(backlog_id)
63
64
  sync do
64
65
  @channels.dup.flat_map do |channel, messages|
65
- messages.select{|id, _| id > backlog_id}.map{|id, value| [id, channel, value]}
66
+ messages.select { |id, _| id > backlog_id }.map { |id, value| [id, channel, value] }
66
67
  end.sort
67
68
  end
68
69
  end
69
70
 
70
71
  def get_value(channel, id)
71
- sync{chan(channel).find{|i, _| i == id}.last}
72
+ sync { chan(channel).find { |i, _| i == id }.last }
72
73
  end
73
74
 
74
75
  # Dangerous, drops the message_bus table containing the backlog if it exists.
@@ -79,7 +80,7 @@ class MessageBus::Memory::Client
79
80
  end
80
81
  end
81
82
 
82
- def max_id(channel=nil)
83
+ def max_id(channel = nil)
83
84
  if channel
84
85
  sync do
85
86
  if entry = chan(channel).last
@@ -87,7 +88,7 @@ class MessageBus::Memory::Client
87
88
  end
88
89
  end
89
90
  else
90
- sync{@global_id - 1}
91
+ sync { @global_id - 1 }
91
92
  end || 0
92
93
  end
93
94
 
@@ -113,7 +114,7 @@ class MessageBus::Memory::Client
113
114
  end
114
115
 
115
116
  def unsubscribe
116
- sync{@listeners.each{|l| l.push(nil)}}
117
+ sync { @listeners.each { |l| l.push(nil) } }
117
118
  end
118
119
 
119
120
  private
@@ -123,7 +124,7 @@ class MessageBus::Memory::Client
123
124
  end
124
125
 
125
126
  def sync
126
- @mutex.synchronize{yield}
127
+ @mutex.synchronize { yield }
127
128
  end
128
129
  end
129
130
 
@@ -163,7 +164,7 @@ class MessageBus::Memory::ReliablePubSub
163
164
  client.reset!
164
165
  end
165
166
 
166
- def publish(channel, data, queue_in_memory=true)
167
+ def publish(channel, data, queue_in_memory = true)
167
168
  client = self.client
168
169
  backlog_id = client.add(channel, data)
169
170
  if backlog_id % clear_every == 0
@@ -232,7 +233,7 @@ class MessageBus::Memory::ReliablePubSub
232
233
  @subscribed = false
233
234
  end
234
235
 
235
- def global_subscribe(last_id=nil, &blk)
236
+ def global_subscribe(last_id = nil, &blk)
236
237
  raise ArgumentError unless block_given?
237
238
  highest_id = last_id
238
239
 
@@ -254,7 +255,7 @@ class MessageBus::Memory::ReliablePubSub
254
255
  @subscribed = false
255
256
  end
256
257
 
257
- on.message do |c,m|
258
+ on.message do |c, m|
258
259
  m = MessageBus::Message.decode m
259
260
 
260
261
  # we have 3 options