message_bus 2.1.5 → 2.1.6
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/CHANGELOG +9 -0
- data/Gemfile +2 -0
- data/README.md +69 -5
- data/assets/message-bus.js +20 -6
- data/lib/message_bus.rb +4 -1
- data/lib/message_bus/distributed_cache.rb +165 -0
- data/lib/message_bus/timer_thread.rb +12 -5
- data/lib/message_bus/version.rb +1 -1
- data/spec/assets/SpecHelper.js +20 -9
- data/spec/assets/message-bus.spec.js +6 -0
- data/spec/lib/message_bus/distributed_cache_spec.rb +133 -0
- data/spec/lib/message_bus/timer_thread_spec.rb +3 -3
- data/spec/lib/message_bus_spec.rb +20 -0
- data/spec/spec_helper.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41c92c01f6f8f8b478877cd97213ceaa9517b28eddb42edc6e421a39d8e6da50
|
4
|
+
data.tar.gz: 00bab454cbce2f3f264eda6470ade5d61bfde42ddbc8709d288da6ee2c204dd8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e009850b2ecd51ed40978993297b67f70e2cb50939e46f165630ce5aa3c1b42170e7ca70f753888218c00ec7fb33dd6ece38900d263f683e2183a66a7cbf0e7a
|
7
|
+
data.tar.gz: 435044844fc8f8620d3ddbac25c5cae390e4ee2988cca28f37fa41da18f12b57293ef7686ecd412af3be23a5a9787e29c459d7bd52548fd1a7bf5378956d5a80
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
15-10-2018
|
2
|
+
|
3
|
+
- Version 2.1.6
|
4
|
+
|
5
|
+
- FEATURE: `MesssageBus.publish` accepts option `site_id` to publish to a site
|
6
|
+
- FEATURE: Added MessageBus::DistributedCache for cross process caching
|
7
|
+
- PERF: Use monotonic times in timer thread
|
8
|
+
- FEATURE: min poll interval is now configurable client side
|
9
|
+
|
1
10
|
16-05-2018
|
2
11
|
|
3
12
|
- Version 2.1.5
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -14,7 +14,6 @@ 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
17
|
## Want to help?
|
19
18
|
|
20
19
|
If you are looking to contribute to this project here are some ideas
|
@@ -119,6 +118,18 @@ MessageBus.user_id_lookup do |env|
|
|
119
118
|
end
|
120
119
|
```
|
121
120
|
|
121
|
+
### Debugging
|
122
|
+
|
123
|
+
When setting up MessageBus, it's good to manually check the channels before integrating the client.
|
124
|
+
|
125
|
+
You can `curl` MessageBus. This is helpful when trying to debug what may be doing wrong. This uses https://chat.samsaffron.com.
|
126
|
+
|
127
|
+
```
|
128
|
+
curl -H "Content-Type: application/x-www-form-urlencoded" -X POST --data "/message=0" https://chat.samsaffron.com/message-bus/client-id/poll\?dlp\=t
|
129
|
+
```
|
130
|
+
|
131
|
+
You should see a reply with the messages of that channel you requested for (`/message`) starting at the message ID (`0`). `dlp=t` disables long-polling: we do not want this request to stay open.
|
132
|
+
|
122
133
|
### Transport
|
123
134
|
|
124
135
|
MessageBus ships with 3 transport mechanisms.
|
@@ -165,7 +176,8 @@ Polling also requires no special setup, MessageBus will fallback to polling afte
|
|
165
176
|
MessageBus can be used in an environment that hosts multiple sites by multiplexing channels. To use this mode
|
166
177
|
|
167
178
|
```ruby
|
168
|
-
# define a site_id lookup method
|
179
|
+
# define a site_id lookup method, which is executed
|
180
|
+
# when `MessageBus.publish` is called
|
169
181
|
MessageBus.configure(site_id_lookup: proc do
|
170
182
|
some_method_that_returns_site_id_string
|
171
183
|
end)
|
@@ -173,6 +185,11 @@ end)
|
|
173
185
|
# you may post messages just to this site
|
174
186
|
MessageBus.publish "/channel", "some message"
|
175
187
|
|
188
|
+
# you can also choose to pass the `site_id`.
|
189
|
+
# This takes precendence over whatever `site_id_lookup`
|
190
|
+
# returns
|
191
|
+
MessageBus.publish "/channel", "some message", site_id: "site-id"
|
192
|
+
|
176
193
|
# you may publish messages to ALL sites using the /global/ prefix
|
177
194
|
MessageBus.publish "/global/channel", "will go to all sites"
|
178
195
|
|
@@ -238,6 +255,7 @@ Setting|Default|Info
|
|
238
255
|
enableLongPolling|true|Allow long-polling (provided it is enable by the server)
|
239
256
|
callbackInterval|15000|Safeguard to ensure background polling does not exceed this interval (in milliseconds)
|
240
257
|
backgroundCallbackInterval|60000|Interval to poll when long polling is disabled (either explicitly or due to browser being in background)
|
258
|
+
minPollInterval|100|When polling requests succeed, this is the minimum amount of time to wait before making the next request.
|
241
259
|
maxPollInterval|180000|If request to the server start failing, MessageBus will backoff, this is the upper limit of the backoff.
|
242
260
|
alwaysLongPoll|false|For debugging you may want to disable the "is browser in background" check and always long-poll
|
243
261
|
baseUrl|/|If message bus is mounted in a subdirectory of different domain, you may configure it to perform requests there
|
@@ -294,13 +312,13 @@ This is configurable via accessors on the ReliablePubSub instance.
|
|
294
312
|
|
295
313
|
```ruby
|
296
314
|
# only store 100 messages per channel
|
297
|
-
MessageBus.
|
315
|
+
MessageBus.reliable_pub_sub.max_backlog_size = 100
|
298
316
|
|
299
317
|
# only store 100 global messages
|
300
|
-
MessageBus.
|
318
|
+
MessageBus.reliable_pub_sub.max_global_backlog_size = 100
|
301
319
|
|
302
320
|
# flush per-channel backlog after 100 seconds of inactivity
|
303
|
-
MessageBus.
|
321
|
+
MessageBus.reliable_pub_sub.max_backlog_age = 100
|
304
322
|
|
305
323
|
```
|
306
324
|
|
@@ -395,6 +413,52 @@ Rails.application.config do |config|
|
|
395
413
|
end
|
396
414
|
```
|
397
415
|
|
416
|
+
### A Distributed Cache
|
417
|
+
|
418
|
+
MessageBus ships with an optional DistributedCache object you can use to synchronize a cache between processes.
|
419
|
+
It allows you a simple and efficient way of synchronizing a cache between processes.
|
420
|
+
|
421
|
+
```ruby
|
422
|
+
require 'message_bus/distributed_cache'
|
423
|
+
|
424
|
+
# process 1
|
425
|
+
|
426
|
+
cache = MessageBus::DistributedCache.new("animals")
|
427
|
+
|
428
|
+
# process 2
|
429
|
+
|
430
|
+
cache = MessageBus::DistributedCache.new("animals")
|
431
|
+
|
432
|
+
# process 1
|
433
|
+
|
434
|
+
cache["frogs"] = 5
|
435
|
+
|
436
|
+
# process 2
|
437
|
+
|
438
|
+
puts cache["frogs"]
|
439
|
+
# => 5
|
440
|
+
|
441
|
+
cache["frogs"] = nil
|
442
|
+
|
443
|
+
# process 1
|
444
|
+
|
445
|
+
puts cache["frogs"]
|
446
|
+
# => nil
|
447
|
+
|
448
|
+
```
|
449
|
+
|
450
|
+
Automatically expiring the cache on app update:
|
451
|
+
|
452
|
+
```ruby
|
453
|
+
cache = MessageBus::DistributedCache.new("cache name", app_version: "12.1.7.ABDEB")
|
454
|
+
cache["a"] = 77
|
455
|
+
|
456
|
+
cache = MessageBus::DistributedCache.new("cache name", app_version: "12.1.7.ABDEF")
|
457
|
+
|
458
|
+
puts cache["a"]
|
459
|
+
# => nil
|
460
|
+
```
|
461
|
+
|
398
462
|
#### Error Handling
|
399
463
|
|
400
464
|
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:
|
data/assets/message-bus.js
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
|
7
7
|
var callbacks, clientId, failCount, shouldLongPoll, queue, responseCallbacks, uniqueId, baseUrl;
|
8
8
|
var me, started, stopped, longPoller, pollTimeout, paused, later, jQuery, interval, chunkedBackoff;
|
9
|
+
var delayPollTimeout;
|
9
10
|
|
10
11
|
var ajaxInProgress = false;
|
11
12
|
|
@@ -277,7 +278,7 @@
|
|
277
278
|
var interval;
|
278
279
|
try {
|
279
280
|
if (gotData || aborted) {
|
280
|
-
interval =
|
281
|
+
interval = me.minPollInterval;
|
281
282
|
} else {
|
282
283
|
interval = me.callbackInterval;
|
283
284
|
if (failCount > 2) {
|
@@ -303,11 +304,16 @@
|
|
303
304
|
|
304
305
|
if (pollTimeout) {
|
305
306
|
clearTimeout(pollTimeout);
|
306
|
-
}
|
307
|
-
pollTimeout = setTimeout(function(){
|
308
307
|
pollTimeout = null;
|
309
|
-
|
310
|
-
|
308
|
+
}
|
309
|
+
|
310
|
+
if (started) {
|
311
|
+
pollTimeout = setTimeout(function(){
|
312
|
+
pollTimeout = null;
|
313
|
+
poll();
|
314
|
+
}, interval);
|
315
|
+
}
|
316
|
+
|
311
317
|
me.longPoll = null;
|
312
318
|
}
|
313
319
|
});
|
@@ -322,6 +328,7 @@
|
|
322
328
|
enableLongPolling: true,
|
323
329
|
callbackInterval: 15000,
|
324
330
|
backgroundCallbackInterval: 60000,
|
331
|
+
minPollInterval: 100,
|
325
332
|
maxPollInterval: 3 * 60 * 1000,
|
326
333
|
callbacks: callbacks,
|
327
334
|
clientId: clientId,
|
@@ -354,11 +361,18 @@
|
|
354
361
|
stop: function() {
|
355
362
|
stopped = true;
|
356
363
|
started = false;
|
364
|
+
if (delayPollTimeout) {
|
365
|
+
clearTimeout(delayPollTimeout);
|
366
|
+
delayPollTimeout = null;
|
367
|
+
}
|
368
|
+
if (me.longPoll) {
|
369
|
+
me.longPoll.abort();
|
370
|
+
}
|
357
371
|
},
|
358
372
|
|
359
373
|
// Start polling
|
360
374
|
start: function() {
|
361
|
-
var poll
|
375
|
+
var poll;
|
362
376
|
|
363
377
|
if (started) return;
|
364
378
|
started = true;
|
data/lib/message_bus.rb
CHANGED
@@ -226,10 +226,12 @@ module MessageBus::Implementation
|
|
226
226
|
group_ids = nil
|
227
227
|
client_ids = nil
|
228
228
|
|
229
|
+
site_id = nil
|
229
230
|
if opts
|
230
231
|
user_ids = opts[:user_ids]
|
231
232
|
group_ids = opts[:group_ids]
|
232
233
|
client_ids = opts[:client_ids]
|
234
|
+
site_id = opts[:site_id]
|
233
235
|
end
|
234
236
|
|
235
237
|
raise ::MessageBus::InvalidMessage if (user_ids || group_ids) && global?(channel)
|
@@ -250,7 +252,8 @@ module MessageBus::Implementation
|
|
250
252
|
}
|
251
253
|
end
|
252
254
|
|
253
|
-
|
255
|
+
encoded_channel_name = encode_channel_name(channel, site_id)
|
256
|
+
reliable_pub_sub.publish(encoded_channel_name, encoded_data, channel_opts)
|
254
257
|
end
|
255
258
|
|
256
259
|
def blocking_subscribe(channel = nil, &blk)
|
@@ -0,0 +1,165 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Like a hash, just does its best to stay in sync across the farm.
|
4
|
+
# On boot all instances are blank, but they populate as various processes
|
5
|
+
# fill it up.
|
6
|
+
|
7
|
+
require 'weakref'
|
8
|
+
require 'base64'
|
9
|
+
require 'securerandom'
|
10
|
+
|
11
|
+
module MessageBus
|
12
|
+
class DistributedCache
|
13
|
+
|
14
|
+
DEFAULT_SITE_ID = 'default'
|
15
|
+
|
16
|
+
class Manager
|
17
|
+
CHANNEL_NAME ||= '/distributed_hash'.freeze
|
18
|
+
|
19
|
+
attr_accessor :app_version
|
20
|
+
|
21
|
+
def initialize(message_bus = nil)
|
22
|
+
@subscribers = []
|
23
|
+
@subscribed = false
|
24
|
+
@lock = Mutex.new
|
25
|
+
@message_bus = message_bus || MessageBus
|
26
|
+
end
|
27
|
+
|
28
|
+
def subscribers
|
29
|
+
@subscribers
|
30
|
+
end
|
31
|
+
|
32
|
+
def process_message(message)
|
33
|
+
i = @subscribers.length - 1
|
34
|
+
|
35
|
+
payload = message.data
|
36
|
+
|
37
|
+
while i >= 0
|
38
|
+
begin
|
39
|
+
current = @subscribers[i]
|
40
|
+
|
41
|
+
next if payload["origin"] == current.identity
|
42
|
+
next if current.key != payload["hash_key"]
|
43
|
+
|
44
|
+
next if @app_version && payload["app_version"] != @app_version
|
45
|
+
|
46
|
+
hash = current.hash(message.site_id || DEFAULT_SITE_ID)
|
47
|
+
|
48
|
+
case payload["op"]
|
49
|
+
when "set" then hash[payload["key"]] = payload["marshalled"] ? Marshal.load(Base64.decode64(payload["value"])) : payload["value"]
|
50
|
+
when "delete" then hash.delete(payload["key"])
|
51
|
+
when "clear" then hash.clear
|
52
|
+
end
|
53
|
+
|
54
|
+
rescue WeakRef::RefError
|
55
|
+
@subscribers.delete_at(i)
|
56
|
+
ensure
|
57
|
+
i -= 1
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def ensure_subscribe!
|
63
|
+
return if @subscribed
|
64
|
+
@lock.synchronize do
|
65
|
+
return if @subscribed
|
66
|
+
@message_bus.subscribe(CHANNEL_NAME) do |message|
|
67
|
+
@lock.synchronize do
|
68
|
+
process_message(message)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
@subscribed = true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def publish(hash, message)
|
76
|
+
message[:origin] = hash.identity
|
77
|
+
message[:hash_key] = hash.key
|
78
|
+
message[:app_version] = @app_version if @app_version
|
79
|
+
@message_bus.publish(CHANNEL_NAME, message, user_ids: [-1])
|
80
|
+
end
|
81
|
+
|
82
|
+
def set(hash, key, value)
|
83
|
+
# special support for set
|
84
|
+
marshal = (Set === value || Hash === value || Array === value)
|
85
|
+
value = Base64.encode64(Marshal.dump(value)) if marshal
|
86
|
+
publish(hash, op: :set, key: key, value: value, marshalled: marshal)
|
87
|
+
end
|
88
|
+
|
89
|
+
def delete(hash, key)
|
90
|
+
publish(hash, op: :delete, key: key)
|
91
|
+
end
|
92
|
+
|
93
|
+
def clear(hash)
|
94
|
+
publish(hash, op: :clear)
|
95
|
+
end
|
96
|
+
|
97
|
+
def register(hash)
|
98
|
+
@lock.synchronize do
|
99
|
+
@subscribers << WeakRef.new(hash)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
@default_manager = Manager.new
|
105
|
+
|
106
|
+
def self.default_manager
|
107
|
+
@default_manager
|
108
|
+
end
|
109
|
+
|
110
|
+
attr_reader :key
|
111
|
+
|
112
|
+
def initialize(key, manager: nil, namespace: true, app_version: nil)
|
113
|
+
@key = key
|
114
|
+
@data = {}
|
115
|
+
@manager = manager || DistributedCache.default_manager
|
116
|
+
@manager.app_version = app_version if app_version
|
117
|
+
@namespace = namespace
|
118
|
+
@app_version = app_version
|
119
|
+
|
120
|
+
@manager.ensure_subscribe!
|
121
|
+
@manager.register(self)
|
122
|
+
end
|
123
|
+
|
124
|
+
def identity
|
125
|
+
# fork resilient / multi machine identity
|
126
|
+
(@seed_id ||= SecureRandom.hex) + "#{Process.pid}"
|
127
|
+
end
|
128
|
+
|
129
|
+
def []=(k, v)
|
130
|
+
k = k.to_s if Symbol === k
|
131
|
+
@manager.set(self, k, v)
|
132
|
+
hash[k] = v
|
133
|
+
end
|
134
|
+
|
135
|
+
def [](k)
|
136
|
+
k = k.to_s if Symbol === k
|
137
|
+
hash[k]
|
138
|
+
end
|
139
|
+
|
140
|
+
def delete(k, publish: true)
|
141
|
+
k = k.to_s if Symbol === k
|
142
|
+
@manager.delete(self, k) if publish
|
143
|
+
hash.delete(k)
|
144
|
+
end
|
145
|
+
|
146
|
+
def clear
|
147
|
+
@manager.clear(self)
|
148
|
+
hash.clear
|
149
|
+
end
|
150
|
+
|
151
|
+
def hash(site_id_arg = nil)
|
152
|
+
site_id =
|
153
|
+
if @namespace
|
154
|
+
site_id_arg ||
|
155
|
+
(MessageBus.site_id_lookup && MessageBus.site_id_lookup.call) ||
|
156
|
+
DEFAULT_SITE_ID
|
157
|
+
else
|
158
|
+
DEFAULT_SITE_ID
|
159
|
+
end
|
160
|
+
|
161
|
+
@data[site_id] ||= {}
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
end
|
@@ -4,7 +4,14 @@ class MessageBus::TimerThread
|
|
4
4
|
attr_reader :jobs
|
5
5
|
|
6
6
|
class Cancelable
|
7
|
-
|
7
|
+
class NoOp
|
8
|
+
def call
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# usually you could just use a blank lambda
|
13
|
+
# but an object is ever so slightly faster
|
14
|
+
NOOP = NoOp.new
|
8
15
|
|
9
16
|
def initialize(job)
|
10
17
|
@job = job
|
@@ -58,7 +65,7 @@ class MessageBus::TimerThread
|
|
58
65
|
|
59
66
|
# queue a block to run after a certain delay (in seconds)
|
60
67
|
def queue(delay = 0, &block)
|
61
|
-
queue_time =
|
68
|
+
queue_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) + delay
|
62
69
|
job = [queue_time, block]
|
63
70
|
|
64
71
|
@mutex.synchronize do
|
@@ -96,7 +103,7 @@ class MessageBus::TimerThread
|
|
96
103
|
|
97
104
|
def do_work
|
98
105
|
while !@stopped
|
99
|
-
if @next && @next <=
|
106
|
+
if @next && @next <= Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
100
107
|
_, blk = @mutex.synchronize { @jobs.shift }
|
101
108
|
begin
|
102
109
|
blk.call
|
@@ -107,10 +114,10 @@ class MessageBus::TimerThread
|
|
107
114
|
@next, _ = @jobs[0]
|
108
115
|
end
|
109
116
|
end
|
110
|
-
unless @next && @next <=
|
117
|
+
unless @next && @next <= Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
111
118
|
sleep_time = 1000
|
112
119
|
@mutex.synchronize do
|
113
|
-
sleep_time = @next -
|
120
|
+
sleep_time = @next - Process.clock_gettime(Process::CLOCK_MONOTONIC) if @next
|
114
121
|
end
|
115
122
|
sleep [0, sleep_time].max
|
116
123
|
end
|
data/lib/message_bus/version.rb
CHANGED
data/spec/assets/SpecHelper.js
CHANGED
@@ -27,6 +27,7 @@ beforeEach(function () {
|
|
27
27
|
function MockedXMLHttpRequest(){
|
28
28
|
this.headers = {};
|
29
29
|
};
|
30
|
+
|
30
31
|
MockedXMLHttpRequest.prototype.send = function(){
|
31
32
|
this.readyState = 4
|
32
33
|
this.responseText = encodeChunks(this, spec.responseChunks);
|
@@ -35,21 +36,38 @@ beforeEach(function () {
|
|
35
36
|
if (this.onprogress){ this.onprogress(); }
|
36
37
|
this.onreadystatechange()
|
37
38
|
}
|
39
|
+
|
38
40
|
MockedXMLHttpRequest.prototype.open = function(){ }
|
39
|
-
|
41
|
+
|
42
|
+
MockedXMLHttpRequest.prototype.abort = function(){
|
43
|
+
this.readyState = 4
|
44
|
+
this.responseText = '';
|
45
|
+
this.statusText = '';
|
46
|
+
this.status = 400;
|
47
|
+
this.onreadystatechange()
|
48
|
+
}
|
49
|
+
|
40
50
|
MockedXMLHttpRequest.prototype.setRequestHeader = function(k,v){
|
41
51
|
this.headers[k] = v;
|
42
52
|
}
|
53
|
+
|
43
54
|
MockedXMLHttpRequest.prototype.getResponseHeader = function(){
|
44
55
|
return 'text/plain; charset=utf-8';
|
45
56
|
}
|
57
|
+
|
46
58
|
MessageBus.xhrImplementation = MockedXMLHttpRequest
|
47
59
|
this.MockedXMLHttpRequest = MockedXMLHttpRequest
|
48
|
-
|
60
|
+
|
49
61
|
this.responseChunks = [
|
50
62
|
{channel: '/test', data: {password: 'MessageBusRocks!'}}
|
51
63
|
];
|
52
64
|
|
65
|
+
MessageBus.start();
|
66
|
+
});
|
67
|
+
|
68
|
+
afterEach(function(){
|
69
|
+
MessageBus.stop()
|
70
|
+
MessageBus.callbacks.splice(0, MessageBus.callbacks.length)
|
53
71
|
});
|
54
72
|
|
55
73
|
window.testMB = function(description, testFn, path, data){
|
@@ -88,10 +106,3 @@ window.testMB = function(description, testFn, path, data){
|
|
88
106
|
|
89
107
|
}
|
90
108
|
|
91
|
-
afterEach(function(){
|
92
|
-
MessageBus.stop()
|
93
|
-
if (MessageBus.longPoll){
|
94
|
-
MessageBus.longPoll.abort();
|
95
|
-
}
|
96
|
-
MessageBus.callbacks.splice(0, MessageBus.callbacks.length)
|
97
|
-
});
|
@@ -84,6 +84,12 @@ describe("Messagebus", function() {
|
|
84
84
|
window.MessageBus = mb;
|
85
85
|
});
|
86
86
|
|
87
|
+
it('respects minPollInterval setting with defaults', function(){
|
88
|
+
expect(MessageBus.minPollInterval).toEqual(100);
|
89
|
+
MessageBus.minPollInterval = 1000;
|
90
|
+
expect(MessageBus.minPollInterval).toEqual(1000);
|
91
|
+
});
|
92
|
+
|
87
93
|
testMB('sends using custom header', function(){
|
88
94
|
MessageBus.headers['X-MB-TEST-VALUE'] = '42';
|
89
95
|
this.perform(function(message, xhr){
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
require 'minitest/hooks/default'
|
3
|
+
require 'message_bus'
|
4
|
+
require 'message_bus/distributed_cache'
|
5
|
+
|
6
|
+
describe MessageBus::DistributedCache do
|
7
|
+
|
8
|
+
before :all do
|
9
|
+
@bus = MessageBus::Instance.new
|
10
|
+
@bus.configure(backend: :memory)
|
11
|
+
@manager = MessageBus::DistributedCache::Manager.new(@bus)
|
12
|
+
end
|
13
|
+
|
14
|
+
after :all do
|
15
|
+
@bus.destroy
|
16
|
+
end
|
17
|
+
|
18
|
+
def cache(name)
|
19
|
+
MessageBus::DistributedCache.new(name, manager: @manager)
|
20
|
+
end
|
21
|
+
|
22
|
+
let :cache_name do
|
23
|
+
SecureRandom.hex
|
24
|
+
end
|
25
|
+
|
26
|
+
before do
|
27
|
+
@cache1 = cache(cache_name)
|
28
|
+
@cache2 = cache(cache_name)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'supports arrays with hashes' do
|
32
|
+
|
33
|
+
c1 = cache("test1")
|
34
|
+
c2 = cache("test1")
|
35
|
+
|
36
|
+
c1["test"] = [{ test: :test }]
|
37
|
+
|
38
|
+
wait_for do
|
39
|
+
c2["test"] == [{ test: :test }]
|
40
|
+
end
|
41
|
+
|
42
|
+
expect(c2[:test]).must_equal([{ test: :test }])
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'allows us to store Set' do
|
46
|
+
c1 = cache("test1")
|
47
|
+
c2 = cache("test1")
|
48
|
+
|
49
|
+
set = Set.new
|
50
|
+
set << 1
|
51
|
+
set << "b"
|
52
|
+
set << 92803984
|
53
|
+
set << 93739739873973
|
54
|
+
|
55
|
+
c1["cats"] = set
|
56
|
+
|
57
|
+
wait_for do
|
58
|
+
c2["cats"] == set
|
59
|
+
end
|
60
|
+
|
61
|
+
expect(c2["cats"]).must_equal(set)
|
62
|
+
|
63
|
+
set << 5
|
64
|
+
|
65
|
+
c2["cats"] = set
|
66
|
+
|
67
|
+
wait_for do
|
68
|
+
c1["cats"] == set
|
69
|
+
end
|
70
|
+
|
71
|
+
expect(c1["cats"]).must_equal(set)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'does not leak state across caches' do
|
75
|
+
c2 = cache("test1")
|
76
|
+
c3 = cache("test1")
|
77
|
+
c2["hi"] = "hi"
|
78
|
+
wait_for do
|
79
|
+
c3["hi"] == "hi"
|
80
|
+
end
|
81
|
+
|
82
|
+
Thread.pass
|
83
|
+
assert_nil(@cache1["hi"])
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'allows coerces symbol keys to strings' do
|
88
|
+
@cache1[:key] = "test"
|
89
|
+
expect(@cache1["key"]).must_equal("test")
|
90
|
+
|
91
|
+
wait_for do
|
92
|
+
@cache2[:key] == "test"
|
93
|
+
end
|
94
|
+
expect(@cache2["key"]).must_equal("test")
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'sets other caches' do
|
98
|
+
@cache1["test"] = "world"
|
99
|
+
wait_for do
|
100
|
+
@cache2["test"] == "world"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'deletes from other caches' do
|
105
|
+
@cache1["foo"] = "bar"
|
106
|
+
|
107
|
+
wait_for do
|
108
|
+
@cache2["foo"] == "bar"
|
109
|
+
end
|
110
|
+
|
111
|
+
@cache1.delete("foo")
|
112
|
+
assert_nil(@cache1["foo"])
|
113
|
+
|
114
|
+
wait_for do
|
115
|
+
@cache2["foo"] == nil
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'clears cache on request' do
|
120
|
+
@cache1["foo"] = "bar"
|
121
|
+
|
122
|
+
wait_for do
|
123
|
+
@cache2["foo"] == "bar"
|
124
|
+
end
|
125
|
+
|
126
|
+
@cache1.clear
|
127
|
+
assert_nil(@cache1["foo"])
|
128
|
+
wait_for do
|
129
|
+
@cache2["boom"] == nil
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
@@ -13,7 +13,7 @@ describe MessageBus::TimerThread do
|
|
13
13
|
it "allows you to queue every jobs" do
|
14
14
|
i = 0
|
15
15
|
m = Mutex.new
|
16
|
-
every = @timer.every(0.001){m.synchronize{i += 1 if i < 3}}
|
16
|
+
every = @timer.every(0.001) { m.synchronize { i += 1 if i < 3 } }
|
17
17
|
# allow lots of time, cause in test mode stuff can be slow
|
18
18
|
wait_for(1000) do
|
19
19
|
m.synchronize do
|
@@ -27,7 +27,7 @@ describe MessageBus::TimerThread do
|
|
27
27
|
|
28
28
|
it "allows you to cancel timers" do
|
29
29
|
success = true
|
30
|
-
@timer.queue(0.005){success=false}.cancel
|
30
|
+
@timer.queue(0.005) { success = false }.cancel
|
31
31
|
sleep(0.006)
|
32
32
|
success.must_equal true
|
33
33
|
end
|
@@ -45,7 +45,7 @@ describe MessageBus::TimerThread do
|
|
45
45
|
4 == results.length
|
46
46
|
}
|
47
47
|
|
48
|
-
results.must_equal [0,1,2,3]
|
48
|
+
results.must_equal [0, 1, 2, 3]
|
49
49
|
end
|
50
50
|
|
51
51
|
it "should call the error callback if something goes wrong" do
|
@@ -159,6 +159,26 @@ describe MessageBus do
|
|
159
159
|
assert_nil @bus.last_message("/nothing")
|
160
160
|
end
|
161
161
|
|
162
|
+
describe "#publish" do
|
163
|
+
it "allows publishing to a explicit site" do
|
164
|
+
data, site_id, channel = nil
|
165
|
+
|
166
|
+
@bus.subscribe do |msg|
|
167
|
+
data = msg.data
|
168
|
+
site_id = msg.site_id
|
169
|
+
channel = msg.channel
|
170
|
+
end
|
171
|
+
|
172
|
+
@bus.publish("/chuck", "norris", site_id: "law-and-order")
|
173
|
+
|
174
|
+
wait_for(2000) { data }
|
175
|
+
|
176
|
+
data.must_equal 'norris'
|
177
|
+
site_id.must_equal 'law-and-order'
|
178
|
+
channel.must_equal '/chuck'
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
162
182
|
describe "global subscriptions" do
|
163
183
|
before do
|
164
184
|
seq = 0
|
data/spec/spec_helper.rb
CHANGED
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.
|
4
|
+
version: 2.1.6
|
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-
|
11
|
+
date: 2018-10-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -95,6 +95,7 @@ files:
|
|
95
95
|
- lib/message_bus/client.rb
|
96
96
|
- lib/message_bus/connection_manager.rb
|
97
97
|
- lib/message_bus/diagnostics.rb
|
98
|
+
- lib/message_bus/distributed_cache.rb
|
98
99
|
- lib/message_bus/em_ext.rb
|
99
100
|
- lib/message_bus/message.rb
|
100
101
|
- lib/message_bus/rack/diagnostics.rb
|
@@ -114,6 +115,7 @@ files:
|
|
114
115
|
- spec/lib/message_bus/backends/redis_spec.rb
|
115
116
|
- spec/lib/message_bus/client_spec.rb
|
116
117
|
- spec/lib/message_bus/connection_manager_spec.rb
|
118
|
+
- spec/lib/message_bus/distributed_cache_spec.rb
|
117
119
|
- spec/lib/message_bus/multi_process_spec.rb
|
118
120
|
- spec/lib/message_bus/rack/middleware_spec.rb
|
119
121
|
- spec/lib/message_bus/timer_thread_spec.rb
|
@@ -157,6 +159,7 @@ test_files:
|
|
157
159
|
- spec/lib/message_bus/backends/redis_spec.rb
|
158
160
|
- spec/lib/message_bus/client_spec.rb
|
159
161
|
- spec/lib/message_bus/connection_manager_spec.rb
|
162
|
+
- spec/lib/message_bus/distributed_cache_spec.rb
|
160
163
|
- spec/lib/message_bus/multi_process_spec.rb
|
161
164
|
- spec/lib/message_bus/rack/middleware_spec.rb
|
162
165
|
- spec/lib/message_bus/timer_thread_spec.rb
|