message_bus 2.0.2 → 2.0.3

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.

@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'pg'
2
3
 
3
4
  module MessageBus::Postgres; end
@@ -30,37 +31,41 @@ class MessageBus::Postgres::Client
30
31
  @pid = Process.pid
31
32
  end
32
33
 
33
- def add(channel, value)
34
- hold{|conn| exec_prepared(conn, 'insert_message', [channel, value]){|r| r.getvalue(0,0).to_i}}
34
+ def add (channel, value)
35
+ hold { |conn| exec_prepared(conn, 'insert_message', [channel, value]) { |r| r.getvalue(0, 0).to_i } }
35
36
  end
36
37
 
37
38
  def clear_global_backlog(backlog_id, num_to_keep)
38
39
  if backlog_id > num_to_keep
39
- hold{|conn| exec_prepared(conn, 'clear_global_backlog', [backlog_id - num_to_keep])}
40
+ hold { |conn| exec_prepared(conn, 'clear_global_backlog', [backlog_id - num_to_keep]) }
40
41
  nil
41
42
  end
42
43
  end
43
44
 
44
45
  def clear_channel_backlog(channel, backlog_id, num_to_keep)
45
- hold{|conn| exec_prepared(conn, 'clear_channel_backlog', [channel, backlog_id, num_to_keep])}
46
+ hold { |conn| exec_prepared(conn, 'clear_channel_backlog', [channel, backlog_id, num_to_keep]) }
46
47
  nil
47
48
  end
48
49
 
49
50
  def expire(max_backlog_age)
50
- hold{|conn| exec_prepared(conn, 'expire', [max_backlog_age])}
51
+ hold { |conn| exec_prepared(conn, 'expire', [max_backlog_age]) }
51
52
  nil
52
53
  end
53
54
 
54
55
  def backlog(channel, backlog_id)
55
- hold{|conn| exec_prepared(conn, 'channel_backlog', [channel, backlog_id]){|r| r.values.each{|a| a[0] = a[0].to_i}}} || []
56
+ hold do |conn|
57
+ exec_prepared(conn, 'channel_backlog', [channel, backlog_id]) { |r| r.values.each { |a| a[0] = a[0].to_i } }
58
+ end || []
56
59
  end
57
60
 
58
61
  def global_backlog(backlog_id)
59
- hold{|conn| exec_prepared(conn, 'global_backlog', [backlog_id]){|r| r.values.each{|a| a[0] = a[0].to_i}}} || []
62
+ hold do |conn|
63
+ exec_prepared(conn, 'global_backlog', [backlog_id]) { |r| r.values.each { |a| a[0] = a[0].to_i } }
64
+ end || []
60
65
  end
61
66
 
62
67
  def get_value(channel, id)
63
- hold{|conn| exec_prepared(conn, 'get_message', [channel, id]){|r| r.getvalue(0,0)}}
68
+ hold { |conn| exec_prepared(conn, 'get_message', [channel, id]) { |r| r.getvalue(0, 0) } }
64
69
  end
65
70
 
66
71
  def reconnect
@@ -78,37 +83,37 @@ class MessageBus::Postgres::Client
78
83
  end
79
84
  end
80
85
 
81
- def max_id(channel=nil)
86
+ def max_id(channel = nil)
82
87
  block = proc do |r|
83
88
  if r.ntuples > 0
84
- r.getvalue(0,0).to_i
89
+ r.getvalue(0, 0).to_i
85
90
  else
86
91
  0
87
92
  end
88
93
  end
89
94
 
90
95
  if channel
91
- hold{|conn| exec_prepared(conn, 'max_channel_id', [channel], &block)}
96
+ hold { |conn| exec_prepared(conn, 'max_channel_id', [channel], &block) }
92
97
  else
93
- hold{|conn| exec_prepared(conn, 'max_id', &block)}
98
+ hold { |conn| exec_prepared(conn, 'max_id', &block) }
94
99
  end
95
100
  end
96
101
 
97
102
  def publish(channel, data)
98
- hold{|conn| exec_prepared(conn, 'publish', [channel, data])}
103
+ hold { |conn| exec_prepared(conn, 'publish', [channel, data]) }
99
104
  end
100
105
 
101
106
  def subscribe(channel)
102
107
  obj = Object.new
103
- sync{@listening_on[channel] = obj}
108
+ sync { @listening_on[channel] = obj }
104
109
  listener = Listener.new
105
110
  yield listener
106
-
111
+
107
112
  conn = raw_pg_connection
108
113
  conn.exec "LISTEN #{channel}"
109
114
  listener.do_sub.call
110
115
  while listening_on?(channel, obj)
111
- conn.wait_for_notify(10) do |_,_,payload|
116
+ conn.wait_for_notify(10) do |_, _, payload|
112
117
  break unless listening_on?(channel, obj)
113
118
  listener.do_message.call(nil, payload)
114
119
  end
@@ -120,7 +125,7 @@ class MessageBus::Postgres::Client
120
125
  end
121
126
 
122
127
  def unsubscribe
123
- sync{@listening_on.clear}
128
+ sync { @listening_on.clear }
124
129
  end
125
130
 
126
131
  private
@@ -149,22 +154,22 @@ class MessageBus::Postgres::Client
149
154
  end
150
155
  end
151
156
 
152
- if conn = sync{@allocated[Thread.current]}
157
+ if conn = sync { @allocated[Thread.current] }
153
158
  return yield(conn)
154
159
  end
155
-
160
+
156
161
  begin
157
- conn = sync{@available.shift} || new_pg_connection
158
- sync{@allocated[Thread.current] = conn}
162
+ conn = sync { @available.shift } || new_pg_connection
163
+ sync { @allocated[Thread.current] = conn }
159
164
  yield conn
160
165
  rescue PG::ConnectionBad, PG::UnableToSend => e
161
166
  # don't add this connection back to the pool
162
167
  ensure
163
- sync{@allocated.delete(Thread.current)}
168
+ sync { @allocated.delete(Thread.current) }
164
169
  if Process.pid != current_pid
165
- sync{INHERITED_CONNECTIONS << conn}
170
+ sync { INHERITED_CONNECTIONS << conn }
166
171
  elsif conn && !e
167
- sync{@available << conn}
172
+ sync { @available << conn }
168
173
  end
169
174
  end
170
175
  end
@@ -197,11 +202,11 @@ class MessageBus::Postgres::Client
197
202
  end
198
203
 
199
204
  def listening_on?(channel, obj)
200
- sync{@listening_on[channel]} == obj
205
+ sync { @listening_on[channel] } == obj
201
206
  end
202
207
 
203
208
  def sync
204
- @mutex.synchronize{yield}
209
+ @mutex.synchronize { yield }
205
210
  end
206
211
  end
207
212
 
@@ -251,7 +256,7 @@ class MessageBus::Postgres::ReliablePubSub
251
256
  client.reset!
252
257
  end
253
258
 
254
- def publish(channel, data, queue_in_memory=true)
259
+ def publish(channel, data, queue_in_memory = true)
255
260
  client = self.client
256
261
  backlog_id = client.add(channel, data)
257
262
  msg = MessageBus::Message.new backlog_id, backlog_id, channel, data
@@ -322,7 +327,7 @@ class MessageBus::Postgres::ReliablePubSub
322
327
  @subscribed = false
323
328
  end
324
329
 
325
- def global_subscribe(last_id=nil, &blk)
330
+ def global_subscribe(last_id = nil, &blk)
326
331
  raise ArgumentError unless block_given?
327
332
  highest_id = last_id
328
333
 
@@ -345,7 +350,7 @@ class MessageBus::Postgres::ReliablePubSub
345
350
  @subscribed = false
346
351
  end
347
352
 
348
- on.message do |c,m|
353
+ on.message do |c, m|
349
354
  if m == UNSUB_MESSAGE
350
355
  @subscribed = false
351
356
  return
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'redis'
2
3
  # the heart of the message bus, it acts as 2 things
3
4
  #
@@ -80,7 +81,7 @@ class MessageBus::Redis::ReliablePubSub
80
81
  end
81
82
  end
82
83
 
83
- def publish(channel, data, queue_in_memory=true)
84
+ def publish(channel, data, queue_in_memory = true)
84
85
  redis = pub_redis
85
86
  backlog_id_key = backlog_id_key(channel)
86
87
  backlog_key = backlog_key(channel)
@@ -122,21 +123,19 @@ class MessageBus::Redis::ReliablePubSub
122
123
  backlog_id
123
124
 
124
125
  rescue Redis::CommandError => e
125
- if queue_in_memory &&
126
- e.message =~ /^READONLY/
127
-
126
+ if queue_in_memory && e.message =~ /^READONLY/
128
127
  @lock.synchronize do
129
- @in_memory_backlog << [channel,data]
128
+ @in_memory_backlog << [channel, data]
130
129
  if @in_memory_backlog.length > @max_in_memory_publish_backlog
131
130
  @in_memory_backlog.delete_at(0)
132
- MessageBus.logger.warn("Dropping old message cause max_in_memory_publish_backlog is full")
131
+ MessageBus.logger.warn("Dropping old message cause max_in_memory_publish_backlog is full: #{e.message}\n#{e.backtrace.join('\n')}")
133
132
  end
134
133
  end
135
134
 
136
135
  if @flush_backlog_thread == nil
137
136
  @lock.synchronize do
138
137
  if @flush_backlog_thread == nil
139
- @flush_backlog_thread = Thread.new{ensure_backlog_flushed}
138
+ @flush_backlog_thread = Thread.new { ensure_backlog_flushed }
140
139
  end
141
140
  end
142
141
  end
@@ -164,15 +163,15 @@ class MessageBus::Redis::ReliablePubSub
164
163
  end
165
164
 
166
165
  begin
167
- publish(*@in_memory_backlog[0],false)
166
+ publish(*@in_memory_backlog[0], false)
168
167
  rescue Redis::CommandError => e
169
168
  if e.message =~ /^READONLY/
170
169
  try_again = true
171
170
  else
172
- MessageBus.logger.warn("Dropping undeliverable message #{e}")
171
+ MessageBus.logger.warn("Dropping undeliverable message: #{e.message}\n#{e.backtrace.join('\n')}")
173
172
  end
174
173
  rescue => e
175
- MessageBus.logger.warn("Dropping undeliverable message #{e}")
174
+ MessageBus.logger.warn("Dropping undeliverable message: #{e.message}\n#{e.backtrace.join('\n')}")
176
175
  end
177
176
 
178
177
  @in_memory_backlog.delete_at(0) unless try_again
@@ -208,7 +207,7 @@ class MessageBus::Redis::ReliablePubSub
208
207
  items.map! do |i|
209
208
  pipe = i.index "|"
210
209
  message_id = i[0..pipe].to_i
211
- channel = i[pipe+1..-1]
210
+ channel = i[pipe + 1..-1]
212
211
  m = get_message(channel, message_id)
213
212
  m
214
213
  end
@@ -277,7 +276,7 @@ class MessageBus::Redis::ReliablePubSub
277
276
  end
278
277
  end
279
278
 
280
- def global_subscribe(last_id=nil, &blk)
279
+ def global_subscribe(last_id = nil, &blk)
281
280
  raise ArgumentError unless block_given?
282
281
  highest_id = last_id
283
282
 
@@ -293,7 +292,6 @@ class MessageBus::Redis::ReliablePubSub
293
292
  end
294
293
  end
295
294
 
296
-
297
295
  begin
298
296
  @redis_global = new_redis_connection
299
297
 
@@ -313,7 +311,7 @@ class MessageBus::Redis::ReliablePubSub
313
311
  @subscribed = false
314
312
  end
315
313
 
316
- on.message do |c,m|
314
+ on.message do |c, m|
317
315
  if m == UNSUB_MESSAGE
318
316
  @redis_global.unsubscribe
319
317
  return
@@ -344,7 +342,7 @@ class MessageBus::Redis::ReliablePubSub
344
342
  private
345
343
 
346
344
  def is_readonly?
347
- key = "__mb_is_readonly".freeze
345
+ key = "__mb_is_readonly"
348
346
 
349
347
  begin
350
348
  # in case we are not connected to the correct server
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class MessageBus::Client
2
3
  attr_accessor :client_id, :user_id, :group_ids, :connect_time,
3
4
  :subscribed_sets, :site_id, :cleanup_timer,
@@ -45,21 +46,21 @@ class MessageBus::Client
45
46
 
46
47
  def ensure_first_chunk_sent
47
48
  if use_chunked && @chunks_sent == 0
48
- write_chunk("[]".freeze)
49
+ write_chunk("[]")
49
50
  end
50
51
  end
51
52
 
52
53
  def ensure_closed!
53
54
  return unless in_async?
54
55
  if use_chunked
55
- write_chunk("[]".freeze)
56
+ write_chunk("[]")
56
57
  if @io
57
- @io.write("0\r\n\r\n".freeze)
58
+ @io.write("0\r\n\r\n")
58
59
  @io.close
59
60
  @io = nil
60
61
  end
61
62
  if @async_response
62
- @async_response << ("0\r\n\r\n".freeze)
63
+ @async_response << ("0\r\n\r\n")
63
64
  @async_response.done
64
65
  @async_response = nil
65
66
  end
@@ -117,21 +118,31 @@ class MessageBus::Client
117
118
 
118
119
  def backlog
119
120
  r = []
120
- @subscriptions.each do |k,v|
121
+ new_message_ids = nil
122
+
123
+ @subscriptions.each do |k, v|
121
124
  next if v.to_i < 0
122
125
  messages = @bus.backlog(k, v, site_id)
126
+
123
127
  messages.each do |msg|
124
- r << msg if allowed?(msg)
128
+ if allowed?(msg)
129
+ r << msg
130
+ else
131
+ new_message_ids ||= {}
132
+ new_message_ids[k] = msg.message_id
133
+ end
125
134
  end
126
135
  end
136
+
127
137
  # stats message for all newly subscribed
128
138
  status_message = nil
129
- @subscriptions.each do |k,v|
130
- if v.to_i == -1
139
+ @subscriptions.each do |k, v|
140
+ if v.to_i == -1 || (new_message_ids && new_message_ids[k])
131
141
  status_message ||= {}
132
142
  @subscriptions[k] = status_message[k] = @bus.last_id(k, site_id)
133
143
  end
134
144
  end
145
+
135
146
  r << MessageBus::Message.new(-1, -1, '/__status', status_message) if status_message
136
147
 
137
148
  r || []
@@ -139,9 +150,8 @@ class MessageBus::Client
139
150
 
140
151
  protected
141
152
 
142
-
143
153
  # heavily optimised to avoid all uneeded allocations
144
- NEWLINE="\r\n".freeze
154
+ NEWLINE = "\r\n".freeze
145
155
  COLON_SPACE = ": ".freeze
146
156
  HTTP_11 = "HTTP/1.1 200 OK\r\n".freeze
147
157
  CONTENT_LENGTH = "Content-Length: ".freeze
@@ -154,7 +164,7 @@ class MessageBus::Client
154
164
 
155
165
  def write_headers
156
166
  @io.write(HTTP_11)
157
- @headers.each do |k,v|
167
+ @headers.each do |k, v|
158
168
  next if k == "Content-Type"
159
169
  @io.write(k)
160
170
  @io.write(COLON_SPACE)
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
1
2
  require 'json' unless defined? ::JSON
2
3
 
3
4
  class MessageBus::ConnectionManager
4
5
  require 'monitor'
5
6
  include MonitorMixin
6
7
 
7
- def initialize(bus=nil)
8
+ def initialize(bus = nil)
8
9
  @clients = {}
9
10
  @subscriptions = {}
10
11
  @bus = bus || MessageBus
@@ -53,7 +54,7 @@ class MessageBus::ConnectionManager
53
54
 
54
55
  @clients[client.client_id] = client
55
56
  @subscriptions[client.site_id] ||= {}
56
- client.subscriptions.each do |k,v|
57
+ client.subscriptions.each do |k, v|
57
58
  subscribe_client(client, k)
58
59
  end
59
60
  end
@@ -79,7 +80,7 @@ class MessageBus::ConnectionManager
79
80
  end
80
81
  end
81
82
 
82
- def subscribe_client(client,channel)
83
+ def subscribe_client(client, channel)
83
84
  synchronize do
84
85
  set = @subscriptions[client.site_id][channel]
85
86
  unless set
@@ -1,18 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class MessageBus::Message < Struct.new(:global_id, :message_id, :channel , :data)
2
4
 
3
5
  attr_accessor :site_id, :user_ids, :group_ids, :client_ids
4
6
 
5
7
  def self.decode(encoded)
6
8
  s1 = encoded.index("|")
7
- s2 = encoded.index("|", s1+1)
8
- s3 = encoded.index("|", s2+1)
9
+ s2 = encoded.index("|", s1 + 1)
10
+ s3 = encoded.index("|", s2 + 1)
9
11
 
10
- MessageBus::Message.new(encoded[0..s1].to_i, encoded[s1+1..s2].to_i,
11
- encoded[s2+1..s3-1].gsub("$$123$$", "|"), encoded[s3+1..-1])
12
+ MessageBus::Message.new(encoded[0..s1].to_i, encoded[(s1 + 1)..s2].to_i,
13
+ encoded[(s2 + 1)..(s3 - 1)].gsub("$$123$$", "|"), encoded[(s3 + 1)..-1])
12
14
  end
13
15
 
14
16
  # only tricky thing to encode is pipes in a channel name ... do a straight replace
15
17
  def encode
16
- global_id.to_s << "|" << message_id.to_s << "|" << channel.gsub("|","$$123$$") << "|" << data
18
+ global_id.to_s << "|" << message_id.to_s << "|" << channel.gsub("|", "$$123$$") << "|" << data
17
19
  end
18
20
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module MessageBus::Rack; end
2
3
 
3
4
  class MessageBus::Rack::Diagnostics
@@ -48,7 +49,7 @@ class MessageBus::Rack::Diagnostics
48
49
  </body>
49
50
  </html>
50
51
  HTML
51
- return [200, {"content-type" => "text/html;"}, [html]]
52
+ return [200, { "content-type" => "text/html;" }, [html]]
52
53
  end
53
54
 
54
55
  def translate_handlebars(name, content)
@@ -80,7 +81,7 @@ HTML
80
81
 
81
82
  if route =~ /^\/hup\//
82
83
  hostname, pid = route.split('/hup/')[1].split('/')
83
- @bus.publish('/_diagnostics/hup', {hostname: hostname, pid: pid.to_i})
84
+ @bus.publish('/_diagnostics/hup', hostname: hostname, pid: pid.to_i)
84
85
  return [200, {}, ['ok']]
85
86
  end
86
87
 
@@ -89,9 +90,9 @@ HTML
89
90
  content = asset_contents(asset)
90
91
  split = asset.split('.')
91
92
  if split[1] == 'handlebars'
92
- content = translate_handlebars(split[0],content)
93
+ content = translate_handlebars(split[0], content)
93
94
  end
94
- return [200, {'content-type' => 'text/javascript;'}, [content]]
95
+ return [200, { 'content-type' => 'text/javascript;' }, [content]]
95
96
  end
96
97
 
97
98
  return [404, {}, ['not found']]