Class: Raidis::RedisWrapper

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

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

Public: Proxies everything to the Redis backend.

Returns whatever the backend returns. Raises Raidis::ConnectionError if there is a connection problem.



11
12
13
14
15
16
# File 'lib/raidis/redis_wrapper.rb', line 11

def method_missing(method, *args, &block)
  raise(Raidis::ConnectionError, 'No Redis backend found.') unless redis
  reloading_connection do
    observing_connection { redis.send(method, *args, &block) }
  end
end

Instance Method Details

#configObject

Internal: Convenience wrapper



109
110
111
# File 'lib/raidis/redis_wrapper.rb', line 109

def config
  Raidis.config
end

#connection_errorsObject

Internal: A list of known connection-related Exceptions the backend may raise.



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/raidis/redis_wrapper.rb', line 66

def connection_errors
  [
    Redis::BaseConnectionError,
    Redis::TimeoutError,
    IOError,
    Timeout::Error,
    Errno::EADDRNOTAVAIL,
    Errno::EAGAIN,
    Errno::EBADF,
    Errno::ECONNABORTED,
    Errno::ECONNREFUSED,
    Errno::ECONNRESET,
    Errno::EHOSTUNREACH,
    Errno::EINVAL,
    Errno::ENETUNREACH,
    Errno::EPIPE,
  ]
end

#observing_connection(&block) ⇒ Object

Internal: Raises a Raidis::ConnectionError if there are connection-related problems during the execution of the block. More specifically, if the connection is lost or a write is performed against a slave, the Exception will be raised.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/raidis/redis_wrapper.rb', line 47

def observing_connection(&block)
  yield

rescue *connection_errors => exception
  Trouble.notify(exception, code: :lost_connection, message: 'Raidis lost connection to the Redis server.', client: redis.inspect) if defined?(Trouble)
  raise Raidis::ConnectionError, exception

rescue Redis::CommandError => exception
  if exception.message.to_s.split.first == 'READONLY'
    Trouble.notify(exception, code: :readonly, message: 'Raidis detected an illegal write against a Redis slave.', client: redis.inspect) if defined?(Trouble)
    raise Raidis::ConnectionError, exception
  else
    # Passing through Exceptions unrelated to the Connection. E.g. Redis::CommandError.
    raise exception
  end
end

#reconnect!Object



85
86
87
# File 'lib/raidis/redis_wrapper.rb', line 85

def reconnect!
  @redis = nil
end

#redisObject

Internal: Establishes a brand-new, raw connection to Redis.

Returns a Redis::Namespace instance or nil if we don’t know where the Redis server is.



97
98
99
# File 'lib/raidis/redis_wrapper.rb', line 97

def redis
  @redis ||= redis!
end

#redis!Object



101
102
103
104
105
# File 'lib/raidis/redis_wrapper.rb', line 101

def redis!
  return unless master = config.master
  raw_redis = Redis.new db: config.redis_db, host: master.endpoint, port: master.port, timeout: config.redis_timeout
  Redis::Namespace.new config.redis_namespace, redis: raw_redis
end

#reloading_connection(&block) ⇒ Object

Internal: If a Raidis::ConnectionError is detected during the execution of the block, try to reconnect to Redis and try again. Updates the availability state.

Returns whatever the block returns. Raises Raidis::ConnectionError if the connection problem persists even after the retries.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/raidis/redis_wrapper.rb', line 24

def reloading_connection(&block)
  tries ||= config.retries
  result = block.call
rescue Raidis::ConnectionError => exception
  # Try again a couple of times.
  throttle.sleep_if_needed
  if (tries -= 1) >= 0
    throttle.action!
    reconnect!
    retry
  end
  # Giving up.
  Raidis.unavailable!
  raise exception
else
  # No exception was raised, reaffirming the availability.
  Raidis.available!
  result
end

#throttleObject



89
90
91
# File 'lib/raidis/redis_wrapper.rb', line 89

def throttle
  @throttle ||= Throttle.new config.retry_interval
end