message_bus 2.2.1 → 2.2.2

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
  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