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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71af05d7950d049061c39abe50a23dd1fe02a51d
|
4
|
+
data.tar.gz: b312ef155c2aacea545f434d4d9e38348bc94ac5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 240897f81ded9f668da49ed7280b378bbe92d17e819e9c795a47affd7e6996a972d61168f4b9c104b8a21b4a01937523d5104661590ab82005de8fa1f39e6c38
|
7
|
+
data.tar.gz: 423409dbf2038a5723438004d451a28b4493edd85eadbf6cd239a0190c11b508ac56eb36be29872be28c2c6b057c31f7e2ba099912153b5cebd0384daf46a517
|
data/Gemfile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
|
3
3
|
group :test do
|
4
4
|
gem "shoulda"
|
@@ -9,11 +9,13 @@ gem "semantic_logger", ">= 2.1"
|
|
9
9
|
gem "resilient_socket"
|
10
10
|
# Doozer Client
|
11
11
|
gem "ruby_doozer"
|
12
|
+
# Zookeeper Client
|
13
|
+
gem "zookeeper"
|
12
14
|
# Thread Safe Hash and Array
|
13
15
|
gem "thread_safe"
|
14
16
|
# Connection pool
|
15
17
|
gem "gene_pool"
|
16
|
-
# For looking up Service entries in
|
18
|
+
# For looking up Service entries in Service Registry
|
17
19
|
gem "multi_json"
|
18
20
|
# Wire format when communicating with services
|
19
21
|
gem "bson"
|
data/Gemfile.lock
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
GEM
|
2
|
-
remote:
|
2
|
+
remote: https://rubygems.org/
|
3
3
|
specs:
|
4
|
-
activesupport (
|
5
|
-
i18n (
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
bson (~> 1.8.6)
|
4
|
+
activesupport (4.0.0)
|
5
|
+
i18n (~> 0.6, >= 0.6.4)
|
6
|
+
minitest (~> 4.2)
|
7
|
+
multi_json (~> 1.3)
|
8
|
+
thread_safe (~> 0.1)
|
9
|
+
tzinfo (~> 0.3.37)
|
10
|
+
atomic (1.1.10-java)
|
11
|
+
bson (1.9.0-java)
|
13
12
|
gene_pool (1.3.0)
|
14
|
-
i18n (0.6.
|
15
|
-
|
16
|
-
|
13
|
+
i18n (0.6.4)
|
14
|
+
minitest (4.7.5)
|
15
|
+
multi_json (1.7.7)
|
16
|
+
rake (10.1.0)
|
17
17
|
resilient_socket (0.5.0)
|
18
18
|
semantic_logger (>= 2.1)
|
19
19
|
ruby_doozer (0.7.1)
|
@@ -30,16 +30,21 @@ GEM
|
|
30
30
|
shoulda (3.5.0)
|
31
31
|
shoulda-context (~> 1.0, >= 1.0.1)
|
32
32
|
shoulda-matchers (>= 1.4.1, < 3.0)
|
33
|
-
shoulda-context (1.1.
|
34
|
-
shoulda-matchers (2.
|
33
|
+
shoulda-context (1.1.4)
|
34
|
+
shoulda-matchers (2.2.0)
|
35
35
|
activesupport (>= 3.0.0)
|
36
|
+
slyphon-log4j (1.2.15)
|
37
|
+
slyphon-zookeeper_jar (3.3.5-java)
|
36
38
|
sync_attr (1.0.0)
|
37
39
|
thread_safe (0.1.0)
|
38
40
|
atomic
|
41
|
+
tzinfo (0.3.37)
|
42
|
+
zookeeper (1.4.4-java)
|
43
|
+
slyphon-log4j (= 1.2.15)
|
44
|
+
slyphon-zookeeper_jar (= 3.3.5)
|
39
45
|
|
40
46
|
PLATFORMS
|
41
47
|
java
|
42
|
-
ruby
|
43
48
|
|
44
49
|
DEPENDENCIES
|
45
50
|
bson
|
@@ -52,3 +57,4 @@ DEPENDENCIES
|
|
52
57
|
semantic_logger (>= 2.1)
|
53
58
|
shoulda
|
54
59
|
thread_safe
|
60
|
+
zookeeper
|
data/README.md
CHANGED
@@ -74,23 +74,27 @@ client = Echo.new
|
|
74
74
|
p client.echo(:hello => 'world')
|
75
75
|
```
|
76
76
|
|
77
|
-
### Architecture
|
78
|
-
|
79
|
-
ruby_skynet implements its own doozer client which has been tested against
|
80
|
-
the doozer fork: https://github.com/4ad/doozerd.
|
81
|
-
The doozer client uses the active [ruby_protobuf](https://github.com/macks/ruby-protobuf)
|
82
|
-
project for marshaling data for communicating with doozer
|
83
|
-
|
84
77
|
### Dependencies
|
85
78
|
|
86
|
-
- Ruby
|
79
|
+
- Ruby 1.8.7, Ruby 1.9.3, Ruby 2.0.0, or JRuby 1.6.3 (or higher)
|
87
80
|
- [SemanticLogger](http://github.com/ClarityServices/semantic_logger)
|
88
81
|
- [ResilientSocket](https://github.com/ClarityServices/resilient_socket)
|
89
|
-
- [ruby_protobuf](https://github.com/macks/ruby-protobuf)
|
90
82
|
- [multi_json](https://github.com/intridea/multi_json)
|
91
83
|
|
84
|
+
One of the following Service Registry Implementations
|
85
|
+
- ZooKeeper Ruby Client [zk](https://github.com/slyphon/zk)
|
86
|
+
- [ruby_doozer](http://github.com/skynetservices/ruby_doozer)
|
87
|
+
|
92
88
|
### Install
|
93
89
|
|
90
|
+
Installing for a ZooKeeper centralized service registry - Recommended
|
91
|
+
|
92
|
+
gem install zk
|
93
|
+
gem install ruby_skynet
|
94
|
+
|
95
|
+
OR, Installing for a Doozer centralized service registry
|
96
|
+
|
97
|
+
gem install ruby_doozer
|
94
98
|
gem install ruby_skynet
|
95
99
|
|
96
100
|
Development
|
data/Rakefile
CHANGED
@@ -28,9 +28,8 @@ task :gem do |t|
|
|
28
28
|
spec.add_dependency 'resilient_socket', '>= 0.5.0'
|
29
29
|
spec.add_dependency 'bson', '>= 1.5.2'
|
30
30
|
spec.add_dependency 'gene_pool', '>= 1.3.0'
|
31
|
+
spec.add_dependency 'zookeeper', '>= 1.4.4'
|
31
32
|
spec.add_dependency 'sync_attr', '>= 1.0.0'
|
32
|
-
spec.add_dependency 'ruby_doozer', '>= 0.7.0'
|
33
|
-
spec.add_dependency 'gene_pool', '>= 1.3.0'
|
34
33
|
end
|
35
34
|
Gem::Package.build gemspec
|
36
35
|
end
|
@@ -18,24 +18,20 @@
|
|
18
18
|
# by remote Skynet clients
|
19
19
|
# Note: Must be an IP address, not the hostname
|
20
20
|
#
|
21
|
-
#
|
22
|
-
# :
|
21
|
+
# Registry settings
|
22
|
+
# :registry
|
23
23
|
# :servers [Array of String]
|
24
24
|
# Array of URL's of doozer servers to connect to with port numbers
|
25
25
|
# ['server1:2000', 'server2:2000']
|
26
26
|
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
# A read failure or timeout will not result in switching to the second
|
30
|
-
# server, only a connection failure or during an automatic reconnect
|
27
|
+
# :connect_timeout [Float]
|
28
|
+
# Time in seconds to timeout when trying to connect to the server
|
31
29
|
#
|
30
|
+
# Additional Doozer configuration options
|
32
31
|
# :read_timeout [Float]
|
33
32
|
# Time in seconds to timeout on read
|
34
33
|
# Can be overridden by supplying a timeout in the read call
|
35
34
|
#
|
36
|
-
# :connect_timeout [Float]
|
37
|
-
# Time in seconds to timeout when trying to connect to the server
|
38
|
-
#
|
39
35
|
# :connect_retry_count [Fixnum]
|
40
36
|
# Number of times to retry connecting when a connection fails
|
41
37
|
#
|
@@ -49,6 +45,10 @@
|
|
49
45
|
# Select a server in the order supplied in the array, with the first
|
50
46
|
# having the highest priority. The second server will only be connected
|
51
47
|
# to if the first server is unreachable
|
48
|
+
# The second server will only be attempted once the first server
|
49
|
+
# cannot be connected to or has timed out on connect
|
50
|
+
# A read failure or timeout will not result in switching to the second
|
51
|
+
# server, only a connection failure or during an automatic reconnect
|
52
52
|
# :random
|
53
53
|
# Randomly select a server from the list every time a connection
|
54
54
|
# is established, including during automatic connection recovery.
|
@@ -60,19 +60,23 @@
|
|
60
60
|
defaults: &defaults
|
61
61
|
:services_path: app/services
|
62
62
|
:server_port: 2000
|
63
|
-
|
63
|
+
|
64
|
+
# Registry Settings
|
65
|
+
:registry:
|
64
66
|
:servers:
|
65
|
-
- 127.0.0.1:
|
66
|
-
:
|
67
|
-
|
68
|
-
|
69
|
-
:
|
70
|
-
:
|
71
|
-
|
72
|
-
:
|
73
|
-
|
74
|
-
:
|
75
|
-
:
|
67
|
+
- 127.0.0.1:2181
|
68
|
+
:connect_timeout: 3
|
69
|
+
|
70
|
+
# Additional Doozer configuration settings
|
71
|
+
# :read_timeout: 5
|
72
|
+
# :connect_retry_count: 10
|
73
|
+
# :connect_retry_interval: 0.5
|
74
|
+
# :server_selector: :random
|
75
|
+
# # Doozer Connection Pool settings
|
76
|
+
# :pool_size: 10
|
77
|
+
# :pool_timeout: 30
|
78
|
+
# :pool_warn_timeout: 2
|
79
|
+
# :pool_idle_timeout: 600
|
76
80
|
|
77
81
|
development:
|
78
82
|
<<: *defaults
|
data/lib/ruby_skynet/client.rb
CHANGED
@@ -88,7 +88,7 @@ module RubySkynet
|
|
88
88
|
retries = 0
|
89
89
|
# If it cannot connect to a server, try a different server
|
90
90
|
begin
|
91
|
-
Connection.with_connection(::RubySkynet.
|
91
|
+
Connection.with_connection(::RubySkynet.service_registry.server_for(skynet_name, skynet_version, skynet_region), connection_params) do |connection|
|
92
92
|
connection.rpc_call(request_id, skynet_name, method_name, parameters)
|
93
93
|
end
|
94
94
|
rescue ResilientSocket::ConnectionFailure => exc
|
@@ -235,7 +235,7 @@ module RubySkynet
|
|
235
235
|
end
|
236
236
|
|
237
237
|
# Cleanup corresponding connection pool when a server terminates
|
238
|
-
RubySkynet.
|
238
|
+
RubySkynet.service_registry.on_server_removed(server) do
|
239
239
|
pool = @@connection_pools.delete(server)
|
240
240
|
# Cannot close all the connections since they could still be in use
|
241
241
|
pool.remove_idle(0) if pool
|
@@ -15,13 +15,18 @@ namespace :ruby_skynet do
|
|
15
15
|
RubySkynet.configure!(cfg_file, environment)
|
16
16
|
end
|
17
17
|
|
18
|
-
# Connect to
|
18
|
+
# Connect to services registry
|
19
19
|
RubySkynet.services
|
20
20
|
|
21
21
|
RubySkynet::Server.load_services
|
22
22
|
|
23
23
|
# Start the server
|
24
24
|
RubySkynet::Server.start
|
25
|
+
|
26
|
+
at_exit do
|
27
|
+
RubySkynet::Server.stop
|
28
|
+
end
|
29
|
+
|
25
30
|
RubySkynet::Server.wait_until_server_stops
|
26
31
|
end
|
27
32
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Define RubySkynet::Registry based on whether the ZooKeeper or Doozer gem is present
|
2
|
+
module RubySkynet
|
3
|
+
begin
|
4
|
+
require 'zookeeper'
|
5
|
+
require 'zookeeper/client'
|
6
|
+
# Monkey-patch so that the Zookeeper JRuby code can handle nil values in Zookeeper
|
7
|
+
require 'ruby_skynet/zookeeper/extensions/java_base' if defined?(::JRUBY_VERSION)
|
8
|
+
Registry = RubySkynet::Zookeeper::Registry
|
9
|
+
rescue LoadError
|
10
|
+
begin
|
11
|
+
require 'ruby_doozer'
|
12
|
+
rescue LoadError
|
13
|
+
raise LoadError, "Must gem install either 'zookeeper' or 'ruby_doozer'. 'zookeeper' is recommended"
|
14
|
+
end
|
15
|
+
Registry = Doozer::Registry
|
16
|
+
end
|
17
|
+
end
|
@@ -45,51 +45,28 @@ module RubySkynet
|
|
45
45
|
@@local_ip_address = local_ip_address
|
46
46
|
end
|
47
47
|
|
48
|
-
# Returns the services registry
|
48
|
+
# Returns the services registry which holds the service names
|
49
49
|
# and the hosts on which they are running
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
)
|
50
|
+
#
|
51
|
+
# By default it connects to a local ZooKeeper instance
|
52
|
+
# Use .configure! to supply a configuration file with any other settings
|
53
|
+
sync_cattr_reader :service_registry do
|
54
|
+
ServiceRegistry.new(:root => '/services')
|
55
55
|
end
|
56
56
|
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
|
61
|
-
|
62
|
-
# Array of URL's of doozer servers to connect to with port numbers
|
63
|
-
# ['server1:2000', 'server2:2000']
|
64
|
-
#
|
65
|
-
# The second server will only be attempted once the first server
|
66
|
-
# cannot be connected to or has timed out on connect
|
67
|
-
# A read failure or timeout will not result in switching to the second
|
68
|
-
# server, only a connection failure or during an automatic reconnect
|
69
|
-
#
|
70
|
-
# :read_timeout [Float]
|
71
|
-
# Time in seconds to timeout on read
|
72
|
-
# Can be overridden by supplying a timeout in the read call
|
73
|
-
#
|
74
|
-
# :connect_timeout [Float]
|
75
|
-
# Time in seconds to timeout when trying to connect to the server
|
76
|
-
#
|
77
|
-
# :connect_retry_count [Fixnum]
|
78
|
-
# Number of times to retry connecting when a connection fails
|
79
|
-
#
|
80
|
-
# :connect_retry_interval [Float]
|
81
|
-
# Number of seconds between connection retry attempts after the first failed attempt
|
82
|
-
sync_cattr_accessor :doozer_config do
|
83
|
-
{
|
84
|
-
:servers => ['127.0.0.1:8046'],
|
85
|
-
:read_timeout => 5,
|
86
|
-
:connect_timeout => 3,
|
87
|
-
:connect_retry_interval => 1,
|
88
|
-
:connect_retry_count => 30
|
89
|
-
}
|
57
|
+
# Set the services registry
|
58
|
+
# It is recommended to call RubySkynet.configure! rather than calling this
|
59
|
+
# method directly
|
60
|
+
def self.service_registry=(service_registry)
|
61
|
+
@@service_registry = service_registry
|
90
62
|
end
|
91
63
|
|
92
|
-
#
|
64
|
+
# DEPRECATED - Use RubySkynet.service_registry
|
65
|
+
def self.services
|
66
|
+
@@service_registry
|
67
|
+
end
|
68
|
+
|
69
|
+
# Load the Configuration information from a YAML file
|
93
70
|
# filename:
|
94
71
|
# Name of file to read.
|
95
72
|
# Mandatory for non-Rails apps
|
@@ -101,16 +78,38 @@ module RubySkynet
|
|
101
78
|
config_file = filename.nil? ? Rails.root.join('config', 'ruby_skynet.yml') : Pathname.new(filename)
|
102
79
|
raise "ruby_skynet config not found. Create a config file at: config/ruby_skynet.yml" unless config_file.file?
|
103
80
|
|
104
|
-
|
105
|
-
raise("Environment #{Rails.env} not defined in config/ruby_skynet.yml") unless
|
81
|
+
config = YAML.load(ERB.new(File.new(config_file).read).result)[environment || Rails.env]
|
82
|
+
raise("Environment #{Rails.env} not defined in config/ruby_skynet.yml") unless config
|
83
|
+
|
84
|
+
@@config = config.dup
|
85
|
+
|
86
|
+
RubySkynet.region = config.delete(:region) || 'Development'
|
87
|
+
RubySkynet.services_path = config.delete(:services_path) || 'app/services'
|
88
|
+
RubySkynet.server_port = config.delete(:server_port) || 2000
|
89
|
+
RubySkynet.local_ip_address = config.delete(:local_ip_address) || Common::local_ip_address
|
106
90
|
|
107
|
-
|
108
|
-
|
109
|
-
RubySkynet.
|
110
|
-
|
111
|
-
|
91
|
+
# Extract just the zookeeper or doozer configuration element
|
92
|
+
key = config[:zookeeper] ? :zookeeper : :doozer
|
93
|
+
RubySkynet.service_registry = ServiceRegistry.new(
|
94
|
+
:root => '/services',
|
95
|
+
key => config.delete(key)
|
96
|
+
)
|
97
|
+
|
98
|
+
config.each_pair {|k,v| RubySkynet::Server.logger.warn "Ignoring unknown RubySkynet config option #{k} => #{v}"}
|
99
|
+
end
|
112
100
|
|
113
|
-
|
101
|
+
# Returns an instance of RubySkynet::Zookeeper::CachedRegistry or RubyDoozer::CachedRegistry
|
102
|
+
# based on which was loaded in RubySkynet.configure!
|
103
|
+
def self.new_cache_registry(root)
|
104
|
+
# Load config
|
105
|
+
service_registry
|
106
|
+
|
107
|
+
if zookeeper = @@config[:zookeeper]
|
108
|
+
RubySkynet::Zookeeper::CachedRegistry.new(:root => root, :zookeeper => zookeeper)
|
109
|
+
else
|
110
|
+
raise "How did we get here", @@config
|
111
|
+
Doozer::CachedRegistry.new(:root => root, :doozer => @@config[:doozer])
|
112
|
+
end
|
114
113
|
end
|
115
114
|
|
116
115
|
end
|
data/lib/ruby_skynet/server.rb
CHANGED
@@ -17,7 +17,7 @@ module RubySkynet
|
|
17
17
|
@@server ||= new(start_port, ip_address)
|
18
18
|
|
19
19
|
# Stop the skynet server on shutdown
|
20
|
-
# To ensure services are de-registered in
|
20
|
+
# To ensure services are de-registered in the service registry
|
21
21
|
at_exit do
|
22
22
|
::RubySkynet::Server.stop
|
23
23
|
end
|
@@ -126,6 +126,18 @@ module RubySkynet
|
|
126
126
|
@listener_thread.join
|
127
127
|
end
|
128
128
|
|
129
|
+
# Registers a Service Class as being available at this server
|
130
|
+
def register_service(klass)
|
131
|
+
logger.info "Registering Service: #{klass.name} with name: #{klass.skynet_name}"
|
132
|
+
::RubySkynet.service_registry.register_service(klass.skynet_name, klass.skynet_version || 1, klass.skynet_region, @hostname, @port)
|
133
|
+
end
|
134
|
+
|
135
|
+
# De-register service from this server
|
136
|
+
def deregister_service(klass)
|
137
|
+
logger.info "De-registering Service: #{klass.name} with name: #{klass.skynet_name}"
|
138
|
+
::RubySkynet.service_registry.deregister_service(klass.skynet_name, klass.skynet_version || 1, klass.skynet_region, @hostname, @port)
|
139
|
+
end
|
140
|
+
|
129
141
|
############################################################################
|
130
142
|
protected
|
131
143
|
|
@@ -204,18 +216,6 @@ module RubySkynet
|
|
204
216
|
logger.debug "Disconnected from the client"
|
205
217
|
end
|
206
218
|
|
207
|
-
# Registers a Service Class as being available at this server
|
208
|
-
def register_service(klass)
|
209
|
-
logger.info "Registering Service: #{klass.name} with name: #{klass.skynet_name}"
|
210
|
-
::RubySkynet.services.register_service(klass.skynet_name, klass.skynet_version || 1, klass.skynet_region, @hostname, @port)
|
211
|
-
end
|
212
|
-
|
213
|
-
# De-register service from this server
|
214
|
-
def deregister_service(klass)
|
215
|
-
logger.info "De-registering Service: #{klass.name} with name: #{klass.skynet_name}"
|
216
|
-
::RubySkynet.services.deregister_service(klass.skynet_name, klass.skynet_version || 1, klass.skynet_region, @hostname, @port)
|
217
|
-
end
|
218
|
-
|
219
219
|
# Called for each message received from the client
|
220
220
|
# Returns a Hash that is sent back to the caller
|
221
221
|
def on_message(skynet_name, method, params)
|
data/lib/ruby_skynet/service.rb
CHANGED
@@ -16,7 +16,7 @@ module RubySkynet
|
|
16
16
|
include SemanticLogger::Loggable
|
17
17
|
end
|
18
18
|
# Register the service with the Server
|
19
|
-
# The server will publish the server to
|
19
|
+
# The server will publish the server to services registry when the server is running
|
20
20
|
Server.register_service(base)
|
21
21
|
end
|
22
22
|
|
@@ -1,8 +1,7 @@
|
|
1
|
-
require '
|
1
|
+
require 'semantic_logger'
|
2
2
|
require 'thread_safe'
|
3
3
|
require 'gene_pool'
|
4
4
|
require 'resolv'
|
5
|
-
require 'ruby_doozer'
|
6
5
|
|
7
6
|
#
|
8
7
|
# RubySkynet Sevices Registry
|
@@ -11,71 +10,37 @@ require 'ruby_doozer'
|
|
11
10
|
# all services and which servers they are available on.
|
12
11
|
#
|
13
12
|
module RubySkynet
|
14
|
-
class ServiceRegistry
|
15
|
-
include SyncAttr
|
13
|
+
class ServiceRegistry
|
16
14
|
include SemanticLogger::Loggable
|
17
15
|
|
18
|
-
IPV4_REG_EXP = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/
|
19
|
-
|
20
|
-
# Returns [Integer] the score for the supplied ip_address
|
21
|
-
# Score currently ranges from 0 to 4 with 4 being the best score
|
22
|
-
# If the IP address does not match an IP v4 address a DNS lookup will
|
23
|
-
# be performed
|
24
|
-
def self.score_for_server(ip_address, local_ip_address)
|
25
|
-
score = 0
|
26
|
-
# Each matching element adds 1 to the score
|
27
|
-
# 192.168. 0. 0
|
28
|
-
# 1
|
29
|
-
# 1
|
30
|
-
# 1
|
31
|
-
# 1
|
32
|
-
server_match = IPV4_REG_EXP.match(ip_address) || IPV4_REG_EXP.match(Resolv::DNS.new.getaddress(ip_address).to_s)
|
33
|
-
if server_match
|
34
|
-
local_match = IPV4_REG_EXP.match(local_ip_address)
|
35
|
-
score = 0
|
36
|
-
(1..4).each do |i|
|
37
|
-
break if local_match[i].to_i != server_match[i].to_i
|
38
|
-
score += 1
|
39
|
-
end
|
40
|
-
end
|
41
|
-
score
|
42
|
-
end
|
43
|
-
|
44
16
|
# Create a service registry
|
45
17
|
# See: RubyDoozer::Registry for the parameters
|
46
18
|
def initialize(params)
|
47
|
-
super
|
48
|
-
|
49
19
|
# Registry has the following format
|
50
20
|
# Key: [String] 'name/version/region'
|
51
21
|
# Value: [Array<String>] 'host:port', 'host:port'
|
52
|
-
@
|
53
|
-
|
54
|
-
path = "#{@root_path}/**"
|
55
|
-
doozer_pool.with_connection do |doozer|
|
56
|
-
@current_revision = doozer.current_revision
|
57
|
-
# Fetch all the configuration information from Doozer and set the internal copy
|
58
|
-
doozer.walk(path, @current_revision) do |path, value|
|
59
|
-
service_info_changed(relative_key(path), value)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# Start monitoring thread
|
64
|
-
monitor_thread
|
22
|
+
@cache = ThreadSafe::Hash.new
|
65
23
|
|
24
|
+
# Supply block to load the current keys from the Registry
|
25
|
+
@registry = Registry.new(params) do |key, value|
|
26
|
+
service_info_changed(key, value)
|
27
|
+
end
|
66
28
|
# Register Callbacks
|
67
|
-
on_update {|path, value| service_info_changed(path, value) }
|
68
|
-
on_delete {|path
|
29
|
+
@registry.on_update {|path, value| service_info_changed(path, value) }
|
30
|
+
@registry.on_delete {|path| service_info_changed(path) }
|
31
|
+
|
32
|
+
# Zookeeper Registry also supports on_create
|
33
|
+
@registry.on_create {|path, value| service_info_changed(path, value) } if @registry.respond_to?(:on_create)
|
69
34
|
end
|
70
35
|
|
71
36
|
# Returns the Service Registry as a Hash
|
72
37
|
def to_h
|
73
|
-
@
|
38
|
+
@cache.dup
|
74
39
|
end
|
75
40
|
|
76
41
|
# Register the supplied service at this Skynet Server host and Port
|
77
42
|
def register_service(name, version, region, hostname, port)
|
78
|
-
|
43
|
+
@registry["#{name}/#{version}/#{region}/#{hostname}/#{port}"] = {
|
79
44
|
"Config" => {
|
80
45
|
"UUID" => "#{hostname}:#{port}-#{$$}-#{name}-#{version}",
|
81
46
|
"Name" => name,
|
@@ -93,7 +58,7 @@ module RubySkynet
|
|
93
58
|
|
94
59
|
# Deregister the supplied service from the Registry
|
95
60
|
def deregister_service(name, version, region, hostname, port)
|
96
|
-
delete("#{name}/#{version}/#{region}/#{hostname}/#{port}")
|
61
|
+
@registry.delete("#{name}/#{version}/#{region}/#{hostname}/#{port}")
|
97
62
|
end
|
98
63
|
|
99
64
|
# Return a server that implements the specified service
|
@@ -113,14 +78,14 @@ module RubySkynet
|
|
113
78
|
if version == '*'
|
114
79
|
# Find the highest version for the named service in this region
|
115
80
|
version = -1
|
116
|
-
@
|
81
|
+
@cache.keys.each do |key|
|
117
82
|
if match = key.match(/#{name}\/(\d+)\/#{region}/)
|
118
83
|
ver = match[1].to_i
|
119
84
|
version = ver if ver > version
|
120
85
|
end
|
121
86
|
end
|
122
87
|
end
|
123
|
-
if server_infos = @
|
88
|
+
if server_infos = @cache["#{name}/#{version}/#{region}"]
|
124
89
|
server_infos.first.servers
|
125
90
|
end
|
126
91
|
end
|
@@ -138,6 +103,7 @@ module RubySkynet
|
|
138
103
|
|
139
104
|
# Service information changed in doozer, so update internal registry
|
140
105
|
def service_info_changed(path, value=nil)
|
106
|
+
logger.info("service_info_changed: #{path}", value)
|
141
107
|
# path: "TutorialService/1/Development/127.0.0.1/9000"
|
142
108
|
e = path.split('/')
|
143
109
|
|
@@ -171,7 +137,7 @@ module RubySkynet
|
|
171
137
|
def add_server(key, hostname, port)
|
172
138
|
server = "#{hostname}:#{port}"
|
173
139
|
|
174
|
-
server_infos = (@
|
140
|
+
server_infos = (@cache[key] ||= ThreadSafe::Array.new)
|
175
141
|
|
176
142
|
# If already present, then nothing to do
|
177
143
|
server_info = server_infos.find{|si| si.servers.include?(server)}
|
@@ -205,7 +171,7 @@ module RubySkynet
|
|
205
171
|
server = "#{hostname}:#{port}"
|
206
172
|
logger.info "Service: #{key} stopped running at #{server}"
|
207
173
|
server_info = nil
|
208
|
-
if server_infos = @
|
174
|
+
if server_infos = @cache[key]
|
209
175
|
server_infos.each do |si|
|
210
176
|
if si.servers.delete(server)
|
211
177
|
server_info = si
|
@@ -219,7 +185,7 @@ module RubySkynet
|
|
219
185
|
server_infos.delete(server_info) if server_info.servers.size == 0
|
220
186
|
|
221
187
|
# Cleanup if no more server infos
|
222
|
-
@
|
188
|
+
@cache.delete(key) if server_infos.size == 0
|
223
189
|
|
224
190
|
server_removed(server) if notify
|
225
191
|
end
|
@@ -241,5 +207,32 @@ module RubySkynet
|
|
241
207
|
end
|
242
208
|
end
|
243
209
|
|
210
|
+
IPV4_REG_EXP = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/
|
211
|
+
|
212
|
+
# Returns [Integer] the score for the supplied ip_address
|
213
|
+
# Score currently ranges from 0 to 4 with 4 being the best score
|
214
|
+
# If the IP address does not match an IP v4 address a DNS lookup will
|
215
|
+
# be performed
|
216
|
+
def self.score_for_server(ip_address, local_ip_address)
|
217
|
+
ip_address = '127.0.0.1' if ip_address == 'localhost'
|
218
|
+
score = 0
|
219
|
+
# Each matching element adds 1 to the score
|
220
|
+
# 192.168. 0. 0
|
221
|
+
# 1
|
222
|
+
# 1
|
223
|
+
# 1
|
224
|
+
# 1
|
225
|
+
server_match = IPV4_REG_EXP.match(ip_address) || IPV4_REG_EXP.match(Resolv::DNS.new.getaddress(ip_address).to_s)
|
226
|
+
if server_match
|
227
|
+
local_match = IPV4_REG_EXP.match(local_ip_address)
|
228
|
+
score = 0
|
229
|
+
(1..4).each do |i|
|
230
|
+
break if local_match[i].to_i != server_match[i].to_i
|
231
|
+
score += 1
|
232
|
+
end
|
233
|
+
end
|
234
|
+
score
|
235
|
+
end
|
236
|
+
|
244
237
|
end
|
245
238
|
end
|
data/lib/ruby_skynet/version.rb
CHANGED