aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/assets/javascripts/cable/connection.coffee19
-rw-r--r--lib/assets/javascripts/cable/connection_monitor.coffee33
2 files changed, 29 insertions, 23 deletions
diff --git a/lib/assets/javascripts/cable/connection.coffee b/lib/assets/javascripts/cable/connection.coffee
index 2259ddcedd..90d8fac3e1 100644
--- a/lib/assets/javascripts/cable/connection.coffee
+++ b/lib/assets/javascripts/cable/connection.coffee
@@ -1,5 +1,7 @@
# Encapsulate the cable connection held by the consumer. This is an internal class not intended for direct user manipulation.
class Cable.Connection
+ @reopenDelay: 500
+
constructor: (@consumer) ->
@open()
@@ -10,19 +12,25 @@ class Cable.Connection
else
false
- open: ->
- if @isOpen()
- throw new Error("Must close existing connection before opening")
+ open: =>
+ if @webSocket and not @isState("closed")
+ throw new Error("Existing connection must be closed before opening")
else
@webSocket = new WebSocket(@consumer.url)
@installEventHandlers()
+ true
close: ->
@webSocket?.close()
reopen: ->
- @close()
- @open()
+ if @isState("closed")
+ @open()
+ else
+ try
+ @close()
+ finally
+ setTimeout(@open, @constructor.reopenDelay)
isOpen: ->
@isState("open")
@@ -40,6 +48,7 @@ class Cable.Connection
for eventName of @events
handler = @events[eventName].bind(this)
@webSocket["on#{eventName}"] = handler
+ return
events:
message: (event) ->
diff --git a/lib/assets/javascripts/cable/connection_monitor.coffee b/lib/assets/javascripts/cable/connection_monitor.coffee
index 30ce11957c..bf99dee34d 100644
--- a/lib/assets/javascripts/cable/connection_monitor.coffee
+++ b/lib/assets/javascripts/cable/connection_monitor.coffee
@@ -1,15 +1,13 @@
# Responsible for ensuring the cable connection is in good health by validating the heartbeat pings sent from the server, and attempting
# revival reconnections if things go astray. Internal class, not intended for direct user manipulation.
class Cable.ConnectionMonitor
- identifier: Cable.PING_IDENTIFIER
-
- pollInterval:
- min: 2
+ @pollInterval:
+ min: 3
max: 30
- staleThreshold:
- startedAt: 4
- pingedAt: 8
+ @staleThreshold: 6 # Server::Connections::BEAT_INTERVAL * 2 (missed two pings)
+
+ identifier: Cable.PING_IDENTIFIER
constructor: (@consumer) ->
@consumer.subscriptions.add(this)
@@ -18,12 +16,10 @@ class Cable.ConnectionMonitor
connected: ->
@reset()
@pingedAt = now()
+ delete @disconnectedAt
disconnected: ->
- if @reconnectAttempts++ is 0
- setTimeout =>
- @consumer.connection.open() unless @consumer.connection.isOpen()
- , 200
+ @disconnectedAt = now()
received: ->
@pingedAt = now()
@@ -50,20 +46,21 @@ class Cable.ConnectionMonitor
, @getInterval()
getInterval: ->
- {min, max} = @pollInterval
- interval = 4 * Math.log(@reconnectAttempts + 1)
+ {min, max} = @constructor.pollInterval
+ interval = 5 * Math.log(@reconnectAttempts + 1)
clamp(interval, min, max) * 1000
reconnectIfStale: ->
if @connectionIsStale()
@reconnectAttempts++
- @consumer.connection.reopen()
+ unless @disconnectedRecently()
+ @consumer.connection.reopen()
connectionIsStale: ->
- if @pingedAt
- secondsSince(@pingedAt) > @staleThreshold.pingedAt
- else
- secondsSince(@startedAt) > @staleThreshold.startedAt
+ secondsSince(@pingedAt ? @startedAt) > @constructor.staleThreshold
+
+ disconnectedRecently: ->
+ @disconnectedAt and secondsSince(@disconnectedAt) < @constructor.staleThreshold
visibilityDidChange: =>
if document.visibilityState is "visible"