diff options
-rw-r--r-- | lib/assets/javascripts/cable/connection.coffee | 19 | ||||
-rw-r--r-- | lib/assets/javascripts/cable/connection_monitor.coffee | 33 |
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" |