提交 96e6de95 编写于 作者: J Javan Makhmali

Defer starting connection monitor until a connection is opened

上级 8e9a1a62
#= require ./connection_monitor
# Encapsulate the cable connection held by the consumer. This is an internal class not intended for direct user manipulation. # Encapsulate the cable connection held by the consumer. This is an internal class not intended for direct user manipulation.
{message_types} = ActionCable.INTERNAL {message_types} = ActionCable.INTERNAL
...@@ -6,6 +8,7 @@ class ActionCable.Connection ...@@ -6,6 +8,7 @@ class ActionCable.Connection
@reopenDelay: 500 @reopenDelay: 500
constructor: (@consumer) -> constructor: (@consumer) ->
@monitor = new ActionCable.ConnectionMonitor this
send: (data) -> send: (data) ->
if @isOpen() if @isOpen()
...@@ -23,6 +26,7 @@ class ActionCable.Connection ...@@ -23,6 +26,7 @@ class ActionCable.Connection
@uninstallEventHandlers() if @webSocket? @uninstallEventHandlers() if @webSocket?
@webSocket = new WebSocket(@consumer.url) @webSocket = new WebSocket(@consumer.url)
@installEventHandlers() @installEventHandlers()
@monitor.start()
true true
close: -> close: ->
...@@ -72,9 +76,9 @@ class ActionCable.Connection ...@@ -72,9 +76,9 @@ class ActionCable.Connection
{identifier, message, type} = JSON.parse(event.data) {identifier, message, type} = JSON.parse(event.data)
switch type switch type
when message_types.welcome when message_types.welcome
@consumer.connectionMonitor.connected() @monitor.recordConnect()
when message_types.ping when message_types.ping
@consumer.connectionMonitor.ping() @monitor.recordPing()
when message_types.confirmation when message_types.confirmation
@consumer.subscriptions.notify(identifier, "connected") @consumer.subscriptions.notify(identifier, "connected")
when message_types.rejection when message_types.rejection
...@@ -98,5 +102,5 @@ class ActionCable.Connection ...@@ -98,5 +102,5 @@ class ActionCable.Connection
disconnect: -> disconnect: ->
return if @disconnected return if @disconnected
@disconnected = true @disconnected = true
@consumer.connectionMonitor.disconnected()
@consumer.subscriptions.notifyAll("disconnected") @consumer.subscriptions.notifyAll("disconnected")
@monitor.recordDisconnect()
...@@ -7,60 +7,69 @@ class ActionCable.ConnectionMonitor ...@@ -7,60 +7,69 @@ class ActionCable.ConnectionMonitor
@staleThreshold: 6 # Server::Connections::BEAT_INTERVAL * 2 (missed two pings) @staleThreshold: 6 # Server::Connections::BEAT_INTERVAL * 2 (missed two pings)
constructor: (@consumer) -> constructor: (@connection) ->
@start() @reconnectAttempts = 0
connected: -> start: ->
@reset() unless @isRunning()
@pingedAt = now() @startedAt = now()
delete @disconnectedAt delete @stoppedAt
ActionCable.log("ConnectionMonitor connected") @startPolling()
document.addEventListener("visibilitychange", @visibilityDidChange)
ActionCable.log("ConnectionMonitor started. pollInterval = #{@getPollInterval()} ms")
disconnected: -> stop: ->
@disconnectedAt = now() if @isRunning()
ActionCable.log("ConnectionMonitor disconnected") @stoppedAt = now()
@stopPolling()
document.removeEventListener("visibilitychange", @visibilityDidChange)
ActionCable.log("ConnectionMonitor stopped")
isRunning: ->
@startedAt? and not @stoppedAt?
ping: -> recordPing: ->
@pingedAt = now() @pingedAt = now()
reset: -> recordConnect: ->
@reconnectAttempts = 0 @reconnectAttempts = 0
@consumer.connection.isOpen() @recordPing()
delete @disconnectedAt
ActionCable.log("ConnectionMonitor recorded connect")
start: -> recordDisconnect: ->
@reset() @disconnectedAt = now()
delete @stoppedAt ActionCable.log("ConnectionMonitor recorded disconnect")
@startedAt = now()
# Private
startPolling: ->
@stopPolling()
@poll() @poll()
document.addEventListener("visibilitychange", @visibilityDidChange)
ActionCable.log("ConnectionMonitor started, pollInterval is #{@getInterval()}ms")
stop: -> stopPolling: ->
@stoppedAt = now() clearTimeout(@pollTimeout)
document.removeEventListener("visibilitychange", @visibilityDidChange)
ActionCable.log("ConnectionMonitor stopped")
poll: -> poll: ->
setTimeout => @pollTimeout = setTimeout =>
unless @stoppedAt @reconnectIfStale()
@reconnectIfStale() @poll()
@poll() , @getPollInterval()
, @getInterval()
getInterval: -> getPollInterval: ->
{min, max} = @constructor.pollInterval {min, max} = @constructor.pollInterval
interval = 5 * Math.log(@reconnectAttempts + 1) interval = 5 * Math.log(@reconnectAttempts + 1)
clamp(interval, min, max) * 1000 Math.round(clamp(interval, min, max) * 1000)
reconnectIfStale: -> reconnectIfStale: ->
if @connectionIsStale() if @connectionIsStale()
ActionCable.log("ConnectionMonitor detected stale connection, reconnectAttempts = #{@reconnectAttempts}") ActionCable.log("ConnectionMonitor detected stale connection. reconnectAttempts = #{@reconnectAttempts}, pollInterval = #{@getPollInterval()} ms, time disconnected = #{secondsSince(@disconnectedAt)} s, stale threshold = #{@constructor.staleThreshold} s")
@reconnectAttempts++ @reconnectAttempts++
if @disconnectedRecently() if @disconnectedRecently()
ActionCable.log("ConnectionMonitor skipping reopen because recently disconnected at #{@disconnectedAt}") ActionCable.log("ConnectionMonitor skipping reopening recent disconnect")
else else
ActionCable.log("ConnectionMonitor reopening") ActionCable.log("ConnectionMonitor reopening")
@consumer.connection.reopen() @connection.reopen()
connectionIsStale: -> connectionIsStale: ->
secondsSince(@pingedAt ? @startedAt) > @constructor.staleThreshold secondsSince(@pingedAt ? @startedAt) > @constructor.staleThreshold
...@@ -71,9 +80,9 @@ class ActionCable.ConnectionMonitor ...@@ -71,9 +80,9 @@ class ActionCable.ConnectionMonitor
visibilityDidChange: => visibilityDidChange: =>
if document.visibilityState is "visible" if document.visibilityState is "visible"
setTimeout => setTimeout =>
if @connectionIsStale() or not @consumer.connection.isOpen() if @connectionIsStale() or not @connection.isOpen()
ActionCable.log("ConnectionMonitor reopening stale connection after visibilitychange to #{document.visibilityState}") ActionCable.log("ConnectionMonitor reopening stale connection on visibilitychange. visbilityState = #{document.visibilityState}")
@consumer.connection.reopen() @connection.reopen()
, 200 , 200
now = -> now = ->
......
#= require ./connection #= require ./connection
#= require ./connection_monitor
#= require ./subscriptions #= require ./subscriptions
#= require ./subscription #= require ./subscription
...@@ -19,7 +18,6 @@ class ActionCable.Consumer ...@@ -19,7 +18,6 @@ class ActionCable.Consumer
constructor: (@url) -> constructor: (@url) ->
@subscriptions = new ActionCable.Subscriptions this @subscriptions = new ActionCable.Subscriptions this
@connection = new ActionCable.Connection this @connection = new ActionCable.Connection this
@connectionMonitor = new ActionCable.ConnectionMonitor this
send: (data) -> send: (data) ->
@connection.send(data) @connection.send(data)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册