Class: Server

Inherits:
Object
  • Object
show all
Defined in:
lib/server.rb

Overview

This class represents a redis server instance.

Constant Summary collapse

RETRY_DELAY =

The amount of time to wait before attempting to re-establish a connection with a server that is marked dead.

30.0

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(host, port = DEFAULT_PORT, timeout = 10) ⇒ Server

Create a new Redis::Server object for the redis instance listening on the given host and port.

Raises:

  • (ArgumentError)


62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/server.rb', line 62

def initialize(host, port = DEFAULT_PORT, timeout = 10)
  raise ArgumentError, "No host specified" if host.nil? or host.empty?
  raise ArgumentError, "No port specified" if port.nil? or port.to_i.zero?

  @host   = host
  @port   = port.to_i

  @sock   = nil
  @retry  = nil
  @status = 'NOT CONNECTED'
  @timeout = timeout
end

Instance Attribute Details

#hostObject (readonly)

The host the redis server is running on.



36
37
38
# File 'lib/server.rb', line 36

def host
  @host
end

#portObject (readonly)

The port the redis server is listening on.



41
42
43
# File 'lib/server.rb', line 41

def port
  @port
end

#replicaObject (readonly)

Returns the value of attribute replica.



46
47
48
# File 'lib/server.rb', line 46

def replica
  @replica
end

#retryObject (readonly)

The time of next retry if the connection is dead.



51
52
53
# File 'lib/server.rb', line 51

def retry
  @retry
end

#statusObject (readonly)

A text status string describing the state of the server.



56
57
58
# File 'lib/server.rb', line 56

def status
  @status
end

Instance Method Details

#closeObject

Close the connection to the redis server targeted by this object. The server is not considered dead.



141
142
143
144
145
146
# File 'lib/server.rb', line 141

def close
  @sock.close if @sock && !@sock.closed?
  @sock   = nil
  @retry  = nil
  @status = "NOT CONNECTED"
end

#connect_to(host, port, timeout = nil) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/server.rb', line 110

def connect_to(host, port, timeout=nil)
  socket = TCPSocket.new(host, port, 0)
  if timeout
    socket.instance_eval <<-EOR
      alias :blocking_gets :gets
      def gets(*args)
        RedisTimer.timeout(#{timeout}) do
          self.blocking_gets(*args)
        end
      end
      alias :blocking_read :read
      def read(*args)
        RedisTimer.timeout(#{timeout}) do
          self.blocking_read(*args)
        end
      end
      alias :blocking_write :write
      def write(*args)
        RedisTimer.timeout(#{timeout}) do
          self.blocking_write(*args)
        end
      end
    EOR
  end
  socket
end

#inspectObject

Return a string representation of the server object.



77
78
79
# File 'lib/server.rb', line 77

def inspect
  "<Redis::Server: %s:%d (%s)>" % [@host, @port, @status]
end

#mark_dead(error) ⇒ Object

Mark the server as dead and close its socket.



150
151
152
153
154
155
156
157
158
# File 'lib/server.rb', line 150

def mark_dead(error)
  @sock.close if @sock && !@sock.closed?
  @sock   = nil
  @retry  = Time.now #+ RETRY_DELAY

  reason = "#{error.class.name}: #{error.message}"
  @status = sprintf "%s:%s DEAD (%s), will retry at %s", @host, @port, reason, @retry
  puts @status
end

#socketObject

Try to connect to the redis server targeted by this object. Returns the connected socket object on success or nil on failure.



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/server.rb', line 85

def socket
  return @sock if @sock and not @sock.closed?

  @sock = nil

  # If the host was dead, don't retry for a while.
  return if @retry and @retry > Time.now

  # Attempt to connect if not already connected.
  begin
    @sock = connect_to(@host, @port, @timeout)
    @sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
    @retry  = nil
    @status = 'CONNECTED'
  rescue Errno::EPIPE, Errno::ECONNREFUSED => e
    puts "Socket died... socket: #{@sock.inspect}\n" if $debug
    @sock.close
    retry
  rescue SocketError, SystemCallError, IOError => err
    puts "Unable to open socket: #{err.class.name}, #{err.message}" if $debug
    mark_dead err
  end
  @sock
end