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) ⇒ Server

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

Raises:

  • (ArgumentError)


41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/server.rb', line 41

def initialize(host, port = DEFAULT_PORT)
  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 = 1
end

Instance Attribute Details

#hostObject (readonly)

The host the redis server is running on.



15
16
17
# File 'lib/server.rb', line 15

def host
  @host
end

#portObject (readonly)

The port the redis server is listening on.



20
21
22
# File 'lib/server.rb', line 20

def port
  @port
end

#replicaObject (readonly)

Returns the value of attribute replica.



25
26
27
# File 'lib/server.rb', line 25

def replica
  @replica
end

#retryObject (readonly)

The time of next retry if the connection is dead.



30
31
32
# File 'lib/server.rb', line 30

def retry
  @retry
end

#statusObject (readonly)

A text status string describing the state of the server.



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

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.



109
110
111
112
113
114
# File 'lib/server.rb', line 109

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

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



90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/server.rb', line 90

def connect_to(host, port, timeout=nil)
  addrs = Socket.getaddrinfo(host, nil)
  addr = addrs.detect { |ad| ad[0] == 'AF_INET' }
  sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
  if timeout
    secs = Integer(timeout)
    usecs = Integer((timeout - secs) * 1_000_000)
    optval = [secs, usecs].pack("l_2")
    sock.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
    sock.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
  end
  sock.connect(Socket.pack_sockaddr_in(port, addr[3]))
  sock
end

#inspectObject

Return a string representation of the server object.



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

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

#mark_dead(error) ⇒ Object

Mark the server as dead and close its socket.



118
119
120
121
122
123
124
125
126
# File 'lib/server.rb', line 118

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.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/server.rb', line 64

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

  return @sock
end