Class: RubyDoozer::Registry

Inherits:
Object
  • Object
show all
Includes:
SemanticLogger::Loggable, SyncAttr
Defined in:
lib/ruby_doozer/registry.rb

Direct Known Subclasses

CachedRegistry

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params, &block) ⇒ Registry

Create a Registry instance to manage a information within doozer

:root [String]

Root key to load and then monitor for changes
It is not recommended to set the root to "/" as it will generate
significant traffic since it will also monitor Doozer Admin changes
Mandatory

:doozer [Hash]

Doozer configuration information

:servers [Array of String]
  Array of URL's of doozer servers to connect to with port numbers
  ['server1:2000', 'server2:2000']

  An attempt will be made to connect to alternative servers when the
  current server cannot be connected to
  Default: ['127.0.0.1:8046']

:read_timeout [Float]
  Time in seconds to timeout on read
  Can be overridden by supplying a timeout in the read call
  Default: 5

:connect_timeout [Float]
  Time in seconds to timeout when trying to connect to the server
  Default: 3

:connect_retry_count [Fixnum]
  Number of times to retry connecting when a connection fails
  Default: 10

:connect_retry_interval [Float]
  Number of seconds between connection retry attempts after the first failed attempt
  Default: 0.5

:server_selector [Symbol|Proc]
  When multiple servers are supplied using :servers, this option will
  determine which server is selected from the list
    :ordered
      Select a server in the order supplied in the array, with the first
      having the highest priority. The second server will only be connected
      to if the first server is unreachable
    :random
      Randomly select a server from the list every time a connection
      is established, including during automatic connection recovery.
    Proc:
      When a Proc is supplied, it will be called passing in the list
      of servers. The Proc must return one server name
        Example:
          :server_selector => Proc.new do |servers|
            servers.last
          end
    Default: :random

:pool_size [Integer]
  Maximum size of the connection pool to doozer
  Default: 10


86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/ruby_doozer/registry.rb', line 86

def initialize(params, &block)
  params = params.dup
  @root = params.delete(:root) || params.delete(:root_path)
  raise "Missing mandatory parameter :root" unless @root

  # Add leading '/' to root if missing
  @root = "/#{@root}" unless @root.start_with?('/')

  # Strip trailing '/' if supplied
  @root = @root[0..-2] if @root.end_with?("/")
  @root_with_trail = "#{@root}/"

  @doozer_config = params.delete(:doozer) || {}
  @doozer_config[:servers]                ||= ['127.0.0.1:8046']
  @doozer_config[:read_timeout]           ||= 5
  @doozer_config[:connect_timeout]        ||= 3
  @doozer_config[:connect_retry_interval] ||= 0.5
  @doozer_config[:connect_retry_count]    ||= 10
  @doozer_config[:server_selector]        ||= :random

  # Allow the serializer and deserializer implementations to be replaced
  @serializer   = params.delete(:serializer)   || RubyDoozer::Json::Serializer
  @deserializer = params.delete(:deserializer) || RubyDoozer::Json::Deserializer

  # Connection pool settings
  @doozer_pool = GenePool.new(
    :name         =>"Doozer Connection Pool",
    :pool_size    => @doozer_config.delete(:pool_size) || 10,
    :timeout      => @doozer_config.delete(:pool_timeout) || 30,
    :warn_timeout => @doozer_config.delete(:pool_warn_timeout) || 5,
    :idle_timeout => @doozer_config.delete(:pool_idle_timeout) || 600,
    :logger       => logger,
    :close_proc   => :close
  ) do
    RubyDoozer::Client.new(@doozer_config)
  end

  # Go through entire registry based on the supplied root path passing
  # all the values to supplied block
  each_pair(&block) if block

  # Generate warning log entries for any unknown configuration options
  params.each_pair {|k,v| logger.warn "Ignoring unknown configuration option: #{k}"}
end

Instance Attribute Details

#current_revisionObject (readonly)

Returns the value of attribute current_revision.



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

def current_revision
  @current_revision
end

#doozer_configObject (readonly)

Returns the value of attribute doozer_config.



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

def doozer_config
  @doozer_config
end

#doozer_poolObject (readonly)

Returns the value of attribute doozer_pool.



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

def doozer_pool
  @doozer_pool
end

#rootObject (readonly)

Returns the value of attribute root.



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

def root
  @root
end

Instance Method Details

#[](key) ⇒ Object

Retrieve the latest value from a specific path from the registry



137
138
139
140
141
142
# File 'lib/ruby_doozer/registry.rb', line 137

def [](key)
  value = doozer_pool.with_connection do |doozer|
    doozer[full_key(key)]
  end
  @deserializer.deserialize(value)
end

#[]=(key, value) ⇒ Object

Replace the latest value at a specific key



145
146
147
148
149
# File 'lib/ruby_doozer/registry.rb', line 145

def []=(key,value)
  doozer_pool.with_connection do |doozer|
    doozer[full_key(key)] = @serializer.serialize(value)
  end
end

#delete(key) ⇒ Object

Delete the value at a specific key



152
153
154
155
156
# File 'lib/ruby_doozer/registry.rb', line 152

def delete(key)
  doozer_pool.with_connection do |doozer|
    doozer.delete(full_key(key))
  end
end

#each_pair(&block) ⇒ Object

Iterate over every key, value pair in the registry at the root

If :cache was set to false on the initializer this call will make network calls to doozer to retrieve the current values Otherwise it is an in memory call against a duplicate of the registry

Example:

registry.each_pair {|k,v| puts "#{k} => #{v}"}


166
167
168
169
170
171
172
173
174
# File 'lib/ruby_doozer/registry.rb', line 166

def each_pair(&block)
  key = "#{@root}/**"
  doozer_pool.with_connection do |doozer|
    current_revision = doozer.current_revision
    doozer.walk(key, current_revision) do |key, value, revision|
      block.call(relative_key(key), @deserializer.deserialize(value), revision)
    end
  end
end

#finalizeObject

Cleanup on process termination



191
192
193
194
195
196
197
198
199
# File 'lib/ruby_doozer/registry.rb', line 191

def finalize
  logger.info "Finalizing"
  if @monitor_thread
    @monitor_thread.kill
    @monitor_thread = nil
  end
  @doozer_pool.close if @doozer_pool
  @doozer_pool = nil
end

#keysObject

Returns [Array<String>] all keys in the registry



177
178
179
180
181
# File 'lib/ruby_doozer/registry.rb', line 177

def keys
  keys = []
  each_pair {|k,v| keys << k}
  keys
end

#on_delete(key = '*', &block) ⇒ Object

When an entry is deleted the block will be called

Parameters
  key
    The relative key to watch for changes
  block
    The block to be called

Parameters passed to the block:
  key
    The key that was deleted from doozer
    Supplying a key of '*' means all paths
    Default: '*'

Example:

registry.on_delete do |key, revision|
  puts "#{key} was deleted"
end


244
245
246
247
248
# File 'lib/ruby_doozer/registry.rb', line 244

def on_delete(key='*', &block)
  # Start monitoring thread if not already started
  monitor_thread
  ((@delete_subscribers ||= ThreadSafe::Hash.new)[key] ||= ThreadSafe::Array.new) << block
end

#on_update(key = '*', &block) ⇒ Object

When an entry is updated the block will be called

Parameters
  key
    The relative key to watch for changes
  block
    The block to be called

Parameters passed to the block:
  key
    The key that was updated in doozer
    Supplying a key of '*' means all paths
    Default: '*'

  value
    New value from doozer

Example:

registry.on_update do |key, value, revision|
  puts "#{key} was updated to #{value}"
end


221
222
223
224
225
# File 'lib/ruby_doozer/registry.rb', line 221

def on_update(key='*', &block)
  # Start monitoring thread if not already started
  monitor_thread
  ((@update_subscribers ||= ThreadSafe::Hash.new)[key] ||= ThreadSafe::Array.new) << block
end

#to_hObject

Returns a copy of the registry as a Hash



184
185
186
187
188
# File 'lib/ruby_doozer/registry.rb', line 184

def to_h
  h = {}
  each_pair {|k,v| h[k] = v}
  h
end