module Strelka::WebSocketServer::Heartbeat

Heartbeat logic for Strelka WebSocketServers.

To ping connected clients, and disconnect them after 3 failed pings:

class ChatServer < Strelka::WebSocketServer
    plugin :heartbeat

    heartbeat_rate 5.0
    idle_timeout 15.0
end

Constants

DEFAULT_HEARTBEAT_RATE

The default number of seconds between heartbeat events

DEFAULT_IDLE_TIMEOUT

The default number of seconds between events before a client is disconnected

Public Instance Methods

cull_idle_sockets() click to toggle source

Disconnect any sockets that haven't sent any frames for at least SOCKET_IDLE_TIMEOUT seconds.

# File lib/strelka/websocketserver/heartbeat.rb, line 119
def cull_idle_sockets
        self.log.debug "Culling idle sockets."

        earliest = Time.now - self.class.idle_timeout

        self.connection_times.each do |sender_id, times|
                times.each do |conn_id, lastframe|
                        next unless earliest > lastframe

                        self.log.warn "Timing out connection %s:%d: last seen %0.3fs ago." %
                                [ sender_id, conn_id, Time.now - lastframe ]

                        # Make a CLOSE frame
                        frame = Mongrel2::WebSocket::Frame.close
                        frame.set_status( CLOSE_EXCEPTION )

                        # Use the connection directly so we can send a frame and close the
                        # connection
                        self.conn.send( sender_id, conn_id, frame.to_s )
                        self.conn.send_close( sender_id, conn_id )
                end
        end
end
ping_all_sockets() click to toggle source

Send a PING frame to all connected sockets.

# File lib/strelka/websocketserver/heartbeat.rb, line 145
def ping_all_sockets
        return if self.connections.empty?

        self.log.debug "Pinging %d connected sockets." % [ self.connections.length ]
        self.connections.each do |sender_id, conn_ids|
                frame = Mongrel2::WebSocket::Frame.new( sender_id, conn_id, '', {}, 'heartbeat' )
                frame.opcode = :ping
                frame.fin = true

                self.log.debug "  %s/%d: PING" % [ sender_id, conn_id ]
                self.conn.reply( frame )
        end

        self.log.debug "  done with pings."
end
restart() click to toggle source

Called by Mongrel2::Handler when the server is restarted. Overridden to restart the heartbeat thread.

Calls superclass method
# File lib/strelka/websocketserver/heartbeat.rb, line 85
def restart
        self.stop_heartbeat
        super
        self.start_heartbeat
end
shutdown() click to toggle source

Called by Mongrel2::Handler when the server is shut down. Overridden to stop the heartbeat thread.

Calls superclass method
# File lib/strelka/websocketserver/heartbeat.rb, line 94
def shutdown
        self.stop_heartbeat
        super
end
start_accepting_requests() click to toggle source

Called by Mongrel2::Handler when it starts accepting requests. Overridden to start up the heartbeat thread.

Calls superclass method
# File lib/strelka/websocketserver/heartbeat.rb, line 77
def start_accepting_requests
        self.start_heartbeat
        super
end
start_heartbeat() click to toggle source

Start a thread that will periodically ping connected sockets and remove any connections that don't reply

# File lib/strelka/websocketserver/heartbeat.rb, line 102
def start_heartbeat
        self.log.info "Starting heartbeat timer."
        @heartbeat_timer = self.reactor.add_periodic_timer( self.class.heartbeat_rate ) do
                self.cull_idle_sockets
                self.ping_all_sockets
        end
end
stop_heartbeat() click to toggle source

Tell the heartbeat thread to exit.

# File lib/strelka/websocketserver/heartbeat.rb, line 112
def stop_heartbeat
        self.reactor.remove_timer( @heartbeat_timer )
end