message_bus 2.2.1 → 2.2.2

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '096c5bb55b64076beef0b89313a6424fb0ded08cb2988f0b79cc44dfc58cc4dd'
4
- data.tar.gz: aceed48ea3dbc555fa4f9896f8cdb474fa543f20469659bc8bf05bcbdd8e20e2
3
+ metadata.gz: 79e90ec066435ef35d00e9184481acdb2a03dbecb41b629dd18584c8a824ae4b
4
+ data.tar.gz: 8d571923665a26165255e06a4a217ad660b39caad101ae3d3755473d740fd3c1
5
5
  SHA512:
6
- metadata.gz: d906c4e50068024c76ea0019f9d376869fba3ea67d52cfae4a49d251f270b442723a3924b78eccdaddcc68963f0c040e91a37d92c9b396f2bf5340b213338328
7
- data.tar.gz: c7ffa6dfd797b20c44e3e305f5de06c04a10a39fc708152c5479b50ca54baf3ebc2b3ff19a08f33949f31390370fded3ea934f39f8c10a0ac22f7a18ac8a341f
6
+ metadata.gz: 4ad3699e51995f038ba76197eed72f9d494f29a3b5ab09be389277cc0b62fe2848eb1d96f090563f75393480768490798c012a16f279f19bbded8b7ea78667d7
7
+ data.tar.gz: 2e8772dc961eefaa746d3569ff57ceecea034c406a4749177c9ba1139ac6575891d8448c00cd7c4f314acd72794cf886ecd5066beb5925a5f7a3b0520270979c
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ Unreleased
2
+
3
+ - Version 2.2.1
4
+
5
+ - FEATURE: Support rate limiting by server, 429 status codes are respected and we hold off as needed
6
+
7
+ - FIX: In the redis backend make the `is_readonly?` method compatible with the redis gem both pre and post v4.0 when the `client` attribute was removed
8
+
1
9
  30-04-2019
2
10
 
3
11
  - Version 2.2.1
@@ -1,20 +1,36 @@
1
1
  /*jshint bitwise: false*/
2
2
  (function(global, document, undefined) {
3
- 'use strict';
3
+ "use strict";
4
4
  var previousMessageBus = global.MessageBus;
5
5
 
6
6
  // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
7
- var callbacks, clientId, failCount, shouldLongPoll, queue, responseCallbacks, uniqueId, baseUrl;
8
- var me, started, stopped, longPoller, pollTimeout, paused, later, jQuery, interval, chunkedBackoff;
7
+ var callbacks,
8
+ clientId,
9
+ failCount,
10
+ shouldLongPoll,
11
+ queue,
12
+ responseCallbacks,
13
+ uniqueId,
14
+ baseUrl;
15
+ var me,
16
+ started,
17
+ stopped,
18
+ longPoller,
19
+ pollTimeout,
20
+ paused,
21
+ later,
22
+ jQuery,
23
+ interval,
24
+ chunkedBackoff;
9
25
  var delayPollTimeout;
10
26
 
11
27
  var ajaxInProgress = false;
12
28
 
13
29
  uniqueId = function() {
14
- return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
30
+ return "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g, function(c) {
15
31
  var r, v;
16
- r = Math.random() * 16 | 0;
17
- v = c === 'x' ? r : (r & 0x3 | 0x8);
32
+ r = (Math.random() * 16) | 0;
33
+ v = c === "x" ? r : (r & 0x3) | 0x8;
18
34
  return v.toString(16);
19
35
  });
20
36
  };
@@ -32,19 +48,19 @@
32
48
  jQuery = global.jQuery;
33
49
  var hiddenProperty;
34
50
 
35
- (function(){
36
- var prefixes = ["","webkit","ms","moz"];
37
- for(var i=0; i<prefixes.length; i++) {
51
+ (function() {
52
+ var prefixes = ["", "webkit", "ms", "moz"];
53
+ for (var i = 0; i < prefixes.length; i++) {
38
54
  var prefix = prefixes[i];
39
55
  var check = prefix + (prefix === "" ? "hidden" : "Hidden");
40
- if(document[check] !== undefined ){
56
+ if (document[check] !== undefined) {
41
57
  hiddenProperty = check;
42
58
  }
43
59
  }
44
60
  })();
45
61
 
46
62
  var isHidden = function() {
47
- if (hiddenProperty !== undefined){
63
+ if (hiddenProperty !== undefined) {
48
64
  return document[hiddenProperty];
49
65
  } else {
50
66
  return !document.hasFocus;
@@ -56,7 +72,7 @@
56
72
  localStorage.setItem("mbTestLocalStorage", Date.now());
57
73
  localStorage.removeItem("mbTestLocalStorage");
58
74
  return true;
59
- } catch(e) {
75
+ } catch (e) {
60
76
  return false;
61
77
  }
62
78
  })();
@@ -65,7 +81,7 @@
65
81
  if (hasLocalStorage) {
66
82
  localStorage.setItem("__mbLastAjax", Date.now());
67
83
  }
68
- }
84
+ };
69
85
 
70
86
  var hiddenTabShouldWait = function() {
71
87
  if (hasLocalStorage && isHidden()) {
@@ -75,10 +91,10 @@
75
91
  return deltaAjax >= 0 && deltaAjax < me.minHiddenPollInterval;
76
92
  }
77
93
  return false;
78
- }
94
+ };
79
95
 
80
- var hasonprogress = (new XMLHttpRequest()).onprogress === null;
81
- var allowChunked = function(){
96
+ var hasonprogress = new XMLHttpRequest().onprogress === null;
97
+ var allowChunked = function() {
82
98
  return me.enableChunkedEncoding && hasonprogress;
83
99
  };
84
100
 
@@ -94,19 +110,23 @@
94
110
  var gotData = false;
95
111
  if (!messages) return false; // server unexpectedly closed connection
96
112
 
97
- for (var i=0; i<messages.length; i++) {
113
+ for (var i = 0; i < messages.length; i++) {
98
114
  var message = messages[i];
99
115
  gotData = true;
100
- for (var j=0; j<callbacks.length; j++) {
116
+ for (var j = 0; j < callbacks.length; j++) {
101
117
  var callback = callbacks[j];
102
118
  if (callback.channel === message.channel) {
103
119
  callback.last_id = message.message_id;
104
120
  try {
105
121
  callback.func(message.data, message.global_id, message.message_id);
106
- }
107
- catch(e){
108
- if(console.log) {
109
- console.log("MESSAGE BUS FAIL: callback " + callback.channel + " caused exception " + e.message);
122
+ } catch (e) {
123
+ if (console.log) {
124
+ console.log(
125
+ "MESSAGE BUS FAIL: callback " +
126
+ callback.channel +
127
+ " caused exception " +
128
+ e.stack
129
+ );
110
130
  }
111
131
  }
112
132
  }
@@ -125,7 +145,7 @@
125
145
  failCount = 0;
126
146
  if (paused) {
127
147
  if (messages) {
128
- for (var i=0; i<messages.length; i++) {
148
+ for (var i = 0; i < messages.length; i++) {
129
149
  later.push(messages[i]);
130
150
  }
131
151
  }
@@ -136,7 +156,6 @@
136
156
  };
137
157
 
138
158
  longPoller = function(poll, data) {
139
-
140
159
  if (ajaxInProgress) {
141
160
  // never allow concurrent ajax reqs
142
161
  return;
@@ -144,6 +163,9 @@
144
163
 
145
164
  var gotData = false;
146
165
  var aborted = false;
166
+ var rateLimited = false;
167
+ var rateLimitedSeconds;
168
+
147
169
  lastAjax = new Date();
148
170
  totalAjaxCalls += 1;
149
171
  data.__seq = totalAjaxCalls;
@@ -156,20 +178,19 @@
156
178
  }
157
179
 
158
180
  var headers = {
159
- 'X-SILENCE-LOGGER': 'true'
181
+ "X-SILENCE-LOGGER": "true"
160
182
  };
161
- for (var name in me.headers){
183
+ for (var name in me.headers) {
162
184
  headers[name] = me.headers[name];
163
185
  }
164
186
 
165
- if (!chunked){
166
- headers["Dont-Chunk"] = 'true';
187
+ if (!chunked) {
188
+ headers["Dont-Chunk"] = "true";
167
189
  }
168
190
 
169
191
  var dataType = chunked ? "text" : "json";
170
192
 
171
193
  var handle_progress = function(payload, position) {
172
-
173
194
  var separator = "\r\n|\r\n";
174
195
  var endChunk = payload.indexOf(separator, position);
175
196
 
@@ -182,7 +203,7 @@
182
203
 
183
204
  try {
184
205
  reqSuccess(JSON.parse(chunk));
185
- } catch(e) {
206
+ } catch (e) {
186
207
  if (console.log) {
187
208
  console.log("FAILED TO PARSE CHUNKED REPLY");
188
209
  console.log(data);
@@ -190,9 +211,9 @@
190
211
  }
191
212
 
192
213
  return handle_progress(payload, endChunk + separator.length);
193
- }
214
+ };
194
215
 
195
- var disableChunked = function(){
216
+ var disableChunked = function() {
196
217
  if (me.longPoll) {
197
218
  me.longPoll.abort();
198
219
  chunkedBackoff = 30;
@@ -203,18 +224,21 @@
203
224
  var position = 0;
204
225
  // if it takes longer than 3000 ms to get first chunk, we have some proxy
205
226
  // this is messing with us, so just backoff from using chunked for now
206
- var chunkedTimeout = setTimeout(disableChunked,3000);
207
- xhr.onprogress = function () {
227
+ var chunkedTimeout = setTimeout(disableChunked, 3000);
228
+ xhr.onprogress = function() {
208
229
  clearTimeout(chunkedTimeout);
209
- if(xhr.getResponseHeader('Content-Type') === 'application/json; charset=utf-8') {
230
+ if (
231
+ xhr.getResponseHeader("Content-Type") ===
232
+ "application/json; charset=utf-8"
233
+ ) {
210
234
  // not chunked we are sending json back
211
235
  chunked = false;
212
236
  return;
213
237
  }
214
238
  position = handle_progress(xhr.responseText, position);
215
- }
239
+ };
216
240
  };
217
- if (!me.ajax){
241
+ if (!me.ajax) {
218
242
  throw new Error("Either jQuery or the ajax adapter must be loaded");
219
243
  }
220
244
 
@@ -222,12 +246,17 @@
222
246
 
223
247
  ajaxInProgress = true;
224
248
  var req = me.ajax({
225
- url: me.baseUrl + "message-bus/" + me.clientId + "/poll" + (!longPoll ? "?dlp=t" : ""),
249
+ url:
250
+ me.baseUrl +
251
+ "message-bus/" +
252
+ me.clientId +
253
+ "/poll" +
254
+ (!longPoll ? "?dlp=t" : ""),
226
255
  data: data,
227
256
  cache: false,
228
257
  async: true,
229
258
  dataType: dataType,
230
- type: 'POST',
259
+ type: "POST",
231
260
  headers: headers,
232
261
  messageBus: {
233
262
  chunked: chunked,
@@ -235,15 +264,18 @@
235
264
  var position = 0;
236
265
  // if it takes longer than 3000 ms to get first chunk, we have some proxy
237
266
  // this is messing with us, so just backoff from using chunked for now
238
- var chunkedTimeout = setTimeout(disableChunked,3000);
239
- return xhr.onprogress = function () {
267
+ var chunkedTimeout = setTimeout(disableChunked, 3000);
268
+ return (xhr.onprogress = function() {
240
269
  clearTimeout(chunkedTimeout);
241
- if(xhr.getResponseHeader('Content-Type') === 'application/json; charset=utf-8') {
270
+ if (
271
+ xhr.getResponseHeader("Content-Type") ===
272
+ "application/json; charset=utf-8"
273
+ ) {
242
274
  chunked = false; // not chunked, we are sending json back
243
275
  } else {
244
276
  position = handle_progress(xhr.responseText, position);
245
277
  }
246
- }
278
+ });
247
279
  }
248
280
  },
249
281
  xhr: function() {
@@ -255,16 +287,27 @@
255
287
  return xhr;
256
288
  },
257
289
  success: function(messages) {
258
- if (!chunked) {
259
- // we may have requested text so jQuery will not parse
260
- if (typeof(messages) === "string") {
261
- messages = JSON.parse(messages);
262
- }
263
- gotData = reqSuccess(messages);
264
- }
265
- },
290
+ if (!chunked) {
291
+ // we may have requested text so jQuery will not parse
292
+ if (typeof messages === "string") {
293
+ messages = JSON.parse(messages);
294
+ }
295
+ gotData = reqSuccess(messages);
296
+ }
297
+ },
266
298
  error: function(xhr, textStatus, err) {
267
- if(textStatus === "abort") {
299
+ if (xhr.status === 429) {
300
+ var tryAfter =
301
+ parseInt(
302
+ xhr.getResponseHeader && xhr.getResponseHeader("Retry-After")
303
+ ) || 0;
304
+ tryAfter = tryAfter || 0;
305
+ if (tryAfter < 15) {
306
+ tryAfter = 15;
307
+ }
308
+ rateLimitedSeconds = tryAfter;
309
+ rateLimited = true;
310
+ } else if (textStatus === "abort") {
268
311
  aborted = true;
269
312
  } else {
270
313
  failCount += 1;
@@ -272,12 +315,13 @@
272
315
  }
273
316
  },
274
317
  complete: function() {
275
-
276
318
  ajaxInProgress = false;
277
319
 
278
320
  var interval;
279
321
  try {
280
- if (gotData || aborted) {
322
+ if (rateLimited) {
323
+ interval = Math.max(me.minPollInterval, rateLimitedSeconds * 1000);
324
+ } else if (gotData || aborted) {
281
325
  interval = me.minPollInterval;
282
326
  } else {
283
327
  interval = me.callbackInterval;
@@ -290,14 +334,14 @@
290
334
  interval = me.maxPollInterval;
291
335
  }
292
336
 
293
- interval -= (new Date() - lastAjax);
337
+ interval -= new Date() - lastAjax;
294
338
 
295
339
  if (interval < 100) {
296
340
  interval = 100;
297
341
  }
298
342
  }
299
- } catch(e) {
300
- if(console.log && e.message) {
343
+ } catch (e) {
344
+ if (console.log && e.message) {
301
345
  console.log("MESSAGE BUS FAIL: " + e.message);
302
346
  }
303
347
  }
@@ -308,7 +352,7 @@
308
352
  }
309
353
 
310
354
  if (started) {
311
- pollTimeout = setTimeout(function(){
355
+ pollTimeout = setTimeout(function() {
312
356
  pollTimeout = null;
313
357
  poll();
314
358
  }, interval);
@@ -335,17 +379,26 @@
335
379
  alwaysLongPoll: false,
336
380
  baseUrl: baseUrl,
337
381
  headers: {},
338
- ajax: (jQuery && jQuery.ajax),
339
- noConflict: function(){
382
+ ajax: jQuery && jQuery.ajax,
383
+ noConflict: function() {
340
384
  global.MessageBus = global.MessageBus.previousMessageBus;
341
385
  return this;
342
386
  },
343
- diagnostics: function(){
387
+ diagnostics: function() {
344
388
  console.log("Stopped: " + stopped + " Started: " + started);
345
389
  console.log("Current callbacks");
346
390
  console.log(callbacks);
347
- console.log("Total ajax calls: " + totalAjaxCalls + " Recent failure count: " + failCount + " Total failures: " + totalAjaxFailures);
348
- console.log("Last ajax call: " + (new Date() - lastAjax) / 1000 + " seconds ago") ;
391
+ console.log(
392
+ "Total ajax calls: " +
393
+ totalAjaxCalls +
394
+ " Recent failure count: " +
395
+ failCount +
396
+ " Total failures: " +
397
+ totalAjaxFailures
398
+ );
399
+ console.log(
400
+ "Last ajax call: " + (new Date() - lastAjax) / 1000 + " seconds ago"
401
+ );
349
402
  },
350
403
 
351
404
  pause: function() {
@@ -381,12 +434,12 @@
381
434
  poll = function() {
382
435
  var data;
383
436
 
384
- if(stopped) {
437
+ if (stopped) {
385
438
  return;
386
439
  }
387
440
 
388
441
  if (callbacks.length === 0 || hiddenTabShouldWait()) {
389
- if(!delayPollTimeout) {
442
+ if (!delayPollTimeout) {
390
443
  delayPollTimeout = setTimeout(function() {
391
444
  delayPollTimeout = null;
392
445
  poll();
@@ -396,7 +449,7 @@
396
449
  }
397
450
 
398
451
  data = {};
399
- for (var i=0;i<callbacks.length;i++) {
452
+ for (var i = 0; i < callbacks.length; i++) {
400
453
  data[callbacks[i].channel] = callbacks[i].last_id;
401
454
  }
402
455
 
@@ -407,30 +460,31 @@
407
460
  }
408
461
  };
409
462
 
410
-
411
463
  // monitor visibility, issue a new long poll when the page shows
412
- if(document.addEventListener && 'hidden' in document){
413
- me.visibilityEvent = global.document.addEventListener('visibilitychange', function(){
414
- if(!document.hidden && !me.longPoll && pollTimeout){
415
-
416
- clearTimeout(pollTimeout);
417
- clearTimeout(delayPollTimeout);
464
+ if (document.addEventListener && "hidden" in document) {
465
+ me.visibilityEvent = global.document.addEventListener(
466
+ "visibilitychange",
467
+ function() {
468
+ if (!document.hidden && !me.longPoll && pollTimeout) {
469
+ clearTimeout(pollTimeout);
470
+ clearTimeout(delayPollTimeout);
418
471
 
419
- delayPollTimeout = null;
420
- pollTimeout = null;
421
- poll();
472
+ delayPollTimeout = null;
473
+ pollTimeout = null;
474
+ poll();
475
+ }
422
476
  }
423
- });
477
+ );
424
478
  }
425
479
 
426
480
  poll();
427
481
  },
428
482
 
429
- "status": function() {
483
+ status: function() {
430
484
  if (paused) {
431
- return "paused";
485
+ return "paused";
432
486
  } else if (started) {
433
- return "started";
487
+ return "started";
434
488
  } else if (stopped) {
435
489
  return "stopped";
436
490
  } else {
@@ -445,16 +499,15 @@
445
499
  // -2 will recieve last message + all new messages
446
500
  // -3 will recieve last 2 messages + all new messages
447
501
  subscribe: function(channel, func, lastId) {
448
-
449
- if(!started && !stopped){
502
+ if (!started && !stopped) {
450
503
  me.start();
451
504
  }
452
505
 
453
- if (typeof(lastId) !== "number") {
506
+ if (typeof lastId !== "number") {
454
507
  lastId = -1;
455
508
  }
456
509
 
457
- if (typeof(channel) !== "string") {
510
+ if (typeof channel !== "string") {
458
511
  throw "Channel name must be a string!";
459
512
  }
460
513
 
@@ -483,8 +536,7 @@
483
536
 
484
537
  var removed = false;
485
538
 
486
- for (var i=callbacks.length-1; i>=0; i--) {
487
-
539
+ for (var i = callbacks.length - 1; i >= 0; i--) {
488
540
  var callback = callbacks[i];
489
541
  var keep;
490
542
 
@@ -494,12 +546,12 @@
494
546
  keep = callback.channel !== channel;
495
547
  }
496
548
 
497
- if(!keep && func && callback.func !== func){
549
+ if (!keep && func && callback.func !== func) {
498
550
  keep = true;
499
551
  }
500
552
 
501
553
  if (!keep) {
502
- callbacks.splice(i,1);
554
+ callbacks.splice(i, 1);
503
555
  removed = true;
504
556
  }
505
557
  }
@@ -433,10 +433,11 @@ LUA
433
433
  key = "__mb_is_readonly"
434
434
 
435
435
  begin
436
+ # disconnect to force a reconnect when attempting to set the key
436
437
  # in case we are not connected to the correct server
437
438
  # which can happen when sharing ips
438
- pub_redis.client.reconnect
439
- pub_redis.client.call([:set, key, '1'])
439
+ pub_redis.disconnect!
440
+ pub_redis.set(key, '1')
440
441
  false
441
442
  rescue ::Redis::CommandError => e
442
443
  return true if e.message =~ /^READONLY/
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MessageBus
4
- VERSION = "2.2.1"
4
+ VERSION = "2.2.2"
5
5
  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.2.1
4
+ version: 2.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-30 00:00:00.000000000 Z
11
+ date: 2019-08-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack