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) ⇒ 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
# File 'lib/ruby_doozer/registry.rb', line 86

def initialize(params)
  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

  # 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



133
134
135
136
137
138
# File 'lib/ruby_doozer/registry.rb', line 133

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



141
142
143
144
145
# File 'lib/ruby_doozer/registry.rb', line 141

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



148
149
150
151
152
# File 'lib/ruby_doozer/registry.rb', line 148

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}"}


162
163
164
165
166
167
168
169
# File 'lib/ruby_doozer/registry.rb', line 162

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

#finalizeObject

Cleanup on process termination



186
187
188
189
190
191
192
193
194
# File 'lib/ruby_doozer/registry.rb', line 186

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



172
173
174
175
176
# File 'lib/ruby_doozer/registry.rb', line 172

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


239
240
241
242
243
# File 'lib/ruby_doozer/registry.rb', line 239

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


216
217
218
219
220
# File 'lib/ruby_doozer/registry.rb', line 216

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



179
180
181
182
183
# File 'lib/ruby_doozer/registry.rb', line 179

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