ruby_skynet 0.8.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +4 -2
- data/Gemfile.lock +22 -16
- data/README.md +13 -9
- data/Rakefile +1 -2
- data/lib/rails/generators/ruby_skynet/config/templates/ruby_skynet.yml +25 -21
- data/lib/ruby_skynet/client.rb +1 -1
- data/lib/ruby_skynet/connection.rb +1 -1
- data/lib/ruby_skynet/railties/ruby_skynet.rake +6 -1
- data/lib/ruby_skynet/registry.rb +17 -0
- data/lib/ruby_skynet/ruby_skynet.rb +47 -48
- data/lib/ruby_skynet/server.rb +13 -13
- data/lib/ruby_skynet/service.rb +1 -1
- data/lib/ruby_skynet/service_registry.rb +48 -55
- data/lib/ruby_skynet/version.rb +1 -1
- data/lib/ruby_skynet/zookeeper/cached_registry.rb +75 -0
- data/lib/ruby_skynet/zookeeper/extensions/java_base.rb +27 -0
- data/lib/ruby_skynet/zookeeper/json/deserializer.rb +64 -0
- data/lib/ruby_skynet/zookeeper/json/serializer.rb +57 -0
- data/lib/ruby_skynet/zookeeper/registry.rb +510 -0
- data/lib/ruby_skynet/zookeeper.rb +11 -0
- data/lib/ruby_skynet.rb +2 -1
- data/test/client_test.rb +1 -1
- data/test/service_registry_test.rb +21 -35
- data/test/zookeeper_registry_test.rb +200 -0
- metadata +16 -23
- data/test.sh +0 -7
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'thread_safe'
|
2
|
+
require 'semantic_logger'
|
3
|
+
require 'ruby_skynet/zookeeper/registry'
|
4
|
+
|
5
|
+
#
|
6
|
+
# CachedRegistry
|
7
|
+
#
|
8
|
+
# Store information in ZooKeeper and subscribe to future changes
|
9
|
+
# and keep a local copy of the information in ZooKeeper
|
10
|
+
#
|
11
|
+
# Notifies registered subscribers when information has changed
|
12
|
+
#
|
13
|
+
# All paths specified are relative to the root_path. As such the root key
|
14
|
+
# is never returned, nor is it required when a key is supplied as input.
|
15
|
+
# For example, with a root_path of /foo/bar, any paths passed in will leave
|
16
|
+
# out the root_path: host/name
|
17
|
+
#
|
18
|
+
# Keeps a local copy in memory of all descendant values of the supplied root_path
|
19
|
+
# Supports high-frequency calls to retrieve registry data
|
20
|
+
# The in-memory cache will be kept in synch with any changes on the server
|
21
|
+
module RubySkynet
|
22
|
+
module Zookeeper
|
23
|
+
class CachedRegistry < Registry
|
24
|
+
# Logging instance for this class
|
25
|
+
include SemanticLogger::Loggable
|
26
|
+
|
27
|
+
# Create a CachedRegistry instance to manage information within the Registry
|
28
|
+
# and keep a local cached copy of the data in the Registry to support
|
29
|
+
# high-speed or frequent reads.
|
30
|
+
#
|
31
|
+
# Writes are sent to ZooKeeper and then replicated back to the local cache
|
32
|
+
# only once ZooKeeper has updated its store
|
33
|
+
#
|
34
|
+
# See RubySkynet::Zookeeper::Registry for the complete list of options
|
35
|
+
#
|
36
|
+
def initialize(params)
|
37
|
+
@cache = ThreadSafe::Hash.new
|
38
|
+
# Supplied block to load the current keys from the Registry
|
39
|
+
super(params) do |key, value, version|
|
40
|
+
@cache[key] = value
|
41
|
+
end
|
42
|
+
|
43
|
+
on_create {|key, value| @cache[key] = value}
|
44
|
+
on_update {|key, value, version| @cache[key] = value}
|
45
|
+
on_delete {|key| @cache.delete(key)}
|
46
|
+
end
|
47
|
+
|
48
|
+
# Retrieve the latest value from a specific key from the registry
|
49
|
+
def [](key)
|
50
|
+
@cache[key]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Iterate over every key, value pair in the registry at the root_path
|
54
|
+
#
|
55
|
+
# Example:
|
56
|
+
# registry.each_pair {|k,v| puts "#{k} => #{v}"}
|
57
|
+
def each_pair(&block)
|
58
|
+
# Have to duplicate the cache otherwise concurrent changes to the
|
59
|
+
# registry will interfere with the iterator
|
60
|
+
@cache.dup.each_pair(&block)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns [Array<String>] all keys in the registry
|
64
|
+
def keys
|
65
|
+
@cache.keys
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns a copy of the registry as a Hash
|
69
|
+
def to_h
|
70
|
+
@cache.dup
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# This monkey-patch must be removed when ticket #44 has been included in
|
2
|
+
# an updated ZooKeeper Gem
|
3
|
+
# Ticket: https://github.com/slyphon/zookeeper/issues/44
|
4
|
+
# Pull Request: https://github.com/slyphon/zookeeper/pull/45
|
5
|
+
|
6
|
+
module Zookeeper
|
7
|
+
class JavaBase
|
8
|
+
|
9
|
+
def get(req_id, path, callback, watcher)
|
10
|
+
handle_keeper_exception do
|
11
|
+
watch_cb = watcher ? create_watcher(req_id, path) : false
|
12
|
+
|
13
|
+
if callback
|
14
|
+
jzk.getData(path, watch_cb, JavaCB::DataCallback.new(req_id), event_queue)
|
15
|
+
[Code::Ok, nil, nil] # the 'nil, nil' isn't strictly necessary here
|
16
|
+
else # sync
|
17
|
+
stat = JZKD::Stat.new
|
18
|
+
value = jzk.getData(path, watch_cb, stat)
|
19
|
+
data = String.from_java_bytes(value) unless value.nil?
|
20
|
+
|
21
|
+
[Code::Ok, data, stat.to_hash]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'multi_json'
|
3
|
+
module RubySkynet
|
4
|
+
module Zookeeper
|
5
|
+
module Json
|
6
|
+
|
7
|
+
# Deserialize from JSON entries in Zookeeper
|
8
|
+
module Deserializer
|
9
|
+
def self.deserialize(value)
|
10
|
+
return value if value.nil? || (value == '')
|
11
|
+
|
12
|
+
if value.strip.start_with?('{') || value.strip.start_with?('[{')
|
13
|
+
symbolize(MultiJson.load(value))
|
14
|
+
else
|
15
|
+
symbolize_string(value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns the supplied value symbolized
|
20
|
+
def self.symbolize(v)
|
21
|
+
if v.is_a?(Hash)
|
22
|
+
symbolize_hash(v)
|
23
|
+
elsif v.is_a?(Array)
|
24
|
+
symbolize_array(v)
|
25
|
+
elsif v.is_a?(String)
|
26
|
+
symbolize_string(v)
|
27
|
+
else
|
28
|
+
v
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns a new hash updated with keys and values that are strings
|
33
|
+
# starting with ':' are turned into symbols
|
34
|
+
def self.symbolize_hash(hash)
|
35
|
+
h = hash.dup
|
36
|
+
hash.each_pair do |k, v|
|
37
|
+
# Convert values in the hash
|
38
|
+
h[k] = symbolize(v)
|
39
|
+
|
40
|
+
# Convert key to a symbol if it is a symbol string
|
41
|
+
h[k[1..-1].to_sym] = h.delete(k) if k.is_a?(String) && k.start_with?(':')
|
42
|
+
end
|
43
|
+
h
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns a new Array with any symbols strings returned as symbols
|
47
|
+
def self.symbolize_array(a)
|
48
|
+
a.collect {|v| symbolize(v)}
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns a new string with the string parsed and symbol string converted to a symbol
|
52
|
+
def self.symbolize_string(s)
|
53
|
+
# JSON Parser cannot parse non-hash/array values
|
54
|
+
value = YAML.load(s)
|
55
|
+
# Now check for symbols which are strings starting with ':'
|
56
|
+
value.is_a?(String) && value.start_with?(':') ? value[1..-1].to_sym : value
|
57
|
+
rescue Exception
|
58
|
+
s
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
module RubySkynet
|
3
|
+
module Zookeeper
|
4
|
+
module Json
|
5
|
+
|
6
|
+
# Serialize to JSON for storing in Doozer
|
7
|
+
module Serializer
|
8
|
+
def self.serialize(value)
|
9
|
+
if value.is_a?(Hash) || value.is_a?(Array)
|
10
|
+
MultiJson.encode(desymbolize(value))
|
11
|
+
elsif value.is_a?(Symbol)
|
12
|
+
desymbolize_symbol(value)
|
13
|
+
else
|
14
|
+
value.to_s
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns the supplied value with symbols converted to a string prefixed
|
19
|
+
# with ':'
|
20
|
+
def self.desymbolize(v)
|
21
|
+
if v.is_a?(Hash)
|
22
|
+
desymbolize_hash(v)
|
23
|
+
elsif v.is_a?(Array)
|
24
|
+
desymbolize_array(v)
|
25
|
+
elsif v.is_a?(Symbol)
|
26
|
+
desymbolize_symbol(v)
|
27
|
+
else
|
28
|
+
v.to_s
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns a new hash with all symbol keys and values as strings starting with ':'
|
33
|
+
def self.desymbolize_hash(hash)
|
34
|
+
h = hash.dup
|
35
|
+
hash.each_pair do |k, v|
|
36
|
+
# Convert values in the hash
|
37
|
+
h[k] = desymbolize(v)
|
38
|
+
|
39
|
+
# Convert key to a string if it is a symbol
|
40
|
+
h[desymbolize_symbol(k)] = h.delete(k) if k.is_a?(Symbol)
|
41
|
+
end
|
42
|
+
h
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns a new Array with any symbols returned as symbol strings
|
46
|
+
def self.desymbolize_array(a)
|
47
|
+
a.collect {|v| desymbolize(v)}
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.desymbolize_symbol(s)
|
51
|
+
":#{s}"
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|