ruby_skynet 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,122 @@
1
+ # Allow test to be run in-place without requiring a gem install
2
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
3
+
4
+ require 'rubygems'
5
+ require 'test/unit'
6
+ require 'shoulda'
7
+ require 'ruby_skynet'
8
+
9
+ # Register an appender if one is not already registered
10
+ if SemanticLogger::Logger.appenders.size == 0
11
+ SemanticLogger::Logger.default_level = :trace
12
+ SemanticLogger::Logger.appenders << SemanticLogger::Appender::File.new('test.log')
13
+ end
14
+
15
+ # Unit Test
16
+ class ServiceRegistryTest < Test::Unit::TestCase
17
+ context RubySkynet::ServiceRegistry do
18
+
19
+ setup do
20
+ @service_name = 'MyRegistryService'
21
+ @version = 5
22
+ @region = 'RegistryTest'
23
+ @hostname = '127.0.0.1'
24
+ @port = 2100
25
+ @service_key = "/services/#{@service_name}/#{@version}/#{@region}/#{@hostname}/#{@port}"
26
+ end
27
+
28
+ context "without a registered service" do
29
+ should "not be in doozer" do
30
+ RubySkynet.services.send(:doozer_pool).with_connection do |doozer|
31
+ assert_equal '', doozer[@service_key]
32
+ end
33
+ end
34
+ end
35
+
36
+ context "with a registered service" do
37
+ setup do
38
+ RubySkynet.services.register_service(@service_name, @version, @region, @hostname, @port)
39
+ # Allow time for doozer callback that service was registered
40
+ sleep 0.1
41
+ end
42
+
43
+ teardown do
44
+ RubySkynet.services.deregister_service(@service_name, @version, @region, @hostname, @port)
45
+ # Allow time for doozer callback that service was deregistered
46
+ sleep 0.1
47
+ # No servers should be in the local registry
48
+ assert_equal nil, RubySkynet.services.servers_for(@service_name, @version, @region)
49
+ end
50
+
51
+ should "find server using exact match" do
52
+ assert servers = RubySkynet.services.servers_for(@service_name, @version, @region)
53
+ assert_equal 1, servers.size
54
+ assert_equal "#{@hostname}:#{@port}", servers.first
55
+ end
56
+
57
+ should "find server using * version match" do
58
+ assert servers = RubySkynet.services.servers_for(@service_name, '*', @region)
59
+ assert_equal 1, servers.size
60
+ assert_equal "#{@hostname}:#{@port}", servers.first
61
+ end
62
+
63
+ context "with multiple servers" do
64
+ setup do
65
+ @second_hostname = '127.0.10.1'
66
+ RubySkynet.services.register_service(@service_name, @version, @region, @hostname, @port+1)
67
+ RubySkynet.services.register_service(@service_name, @version, @region, @hostname, @port+3)
68
+ RubySkynet.services.register_service(@service_name, @version-1, @region, @hostname, @port+2)
69
+ RubySkynet.services.register_service(@service_name, @version, @region, @second_hostname, @port)
70
+ end
71
+
72
+ teardown do
73
+ RubySkynet.services.deregister_service(@service_name, @version, @region, @hostname, @port+1)
74
+ RubySkynet.services.deregister_service(@service_name, @version, @region, @hostname, @port+3)
75
+ RubySkynet.services.deregister_service(@service_name, @version-1, @region, @hostname, @port+2)
76
+ RubySkynet.services.deregister_service(@service_name, @version, @region, @second_hostname, @port)
77
+ end
78
+
79
+ should "using * version match" do
80
+ assert servers = RubySkynet.services.servers_for(@service_name, '*', @region)
81
+ assert_equal 3, servers.size, RubySkynet.services.to_h.to_s
82
+ assert_equal "#{@hostname}:#{@port}", servers.first
83
+ assert_equal "#{@hostname}:#{@port+3}", servers.last
84
+ end
85
+ end
86
+
87
+ should "return nil when service not found" do
88
+ assert_equal nil, RubySkynet.services.servers_for('MissingService', @version, @region)
89
+ end
90
+
91
+ should "return nil when version not found" do
92
+ assert_equal nil, RubySkynet.services.servers_for(@service_name, @version+1, @region)
93
+ end
94
+
95
+ should "return nil when region not found" do
96
+ assert_equal nil, RubySkynet.services.servers_for(@service_name, @version, 'OtherRegion')
97
+ end
98
+
99
+ should "be in doozer" do
100
+ RubySkynet.services.send(:doozer_pool).with_connection do |doozer|
101
+ assert_equal true, doozer[@service_key].length > 20
102
+ end
103
+ end
104
+ end
105
+
106
+ context "scoring" do
107
+ [
108
+ ['192.168.11.0', 4 ],
109
+ ['192.168.11.10', 3 ],
110
+ ['192.168.10.0', 2 ],
111
+ ['192.5.10.0', 1 ],
112
+ ['10.0.11.0', 0 ],
113
+ ].each do |test|
114
+ should "handle score #{test[1]}" do
115
+ local_ip_address = "192.168.11.0"
116
+ assert_equal test[1], RubySkynet::ServiceRegistry.score_for_server(test[0], local_ip_address), "Local: #{local_ip_address} Server: #{test[0]} Score: #{test[1]}"
117
+ end
118
+ end
119
+ end
120
+
121
+ end
122
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_skynet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-03-27 00:00:00.000000000 Z
11
+ date: 2013-04-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: semantic_logger
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - '>='
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 2.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: 2.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: resilient_socket
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '>='
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 0.4.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '>='
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 0.4.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: multi_json
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,42 +58,42 @@ dependencies:
58
58
  requirements:
59
59
  - - '>='
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: 1.5.2
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - '>='
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: 1.5.2
69
69
  - !ruby/object:Gem::Dependency
70
- name: ruby_protobuf
70
+ name: ruby_doozer
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - '>='
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: 0.5.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - '>='
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: 0.5.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: gene_pool
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - '>='
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: 1.3.0
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - '>='
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: 1.3.0
97
97
  description: Ruby Client for invoking Skynet services
98
98
  email:
99
99
  - reidmo@gmail.com
@@ -106,7 +106,6 @@ files:
106
106
  - LICENSE.txt
107
107
  - README.md
108
108
  - Rakefile
109
- - examples/e.rb
110
109
  - examples/echo_client.rb
111
110
  - examples/echo_server.rb
112
111
  - lib/rails/generators/ruby_skynet/config/config_generator.rb
@@ -116,22 +115,18 @@ files:
116
115
  - lib/ruby_skynet/client.rb
117
116
  - lib/ruby_skynet/common.rb
118
117
  - lib/ruby_skynet/connection.rb
119
- - lib/ruby_skynet/doozer/client.rb
120
- - lib/ruby_skynet/doozer/exceptions.rb
121
- - lib/ruby_skynet/doozer/msg.pb.rb
122
118
  - lib/ruby_skynet/exceptions.rb
123
119
  - lib/ruby_skynet/railtie.rb
124
120
  - lib/ruby_skynet/railties/ruby_skynet.rake
125
- - lib/ruby_skynet/registry.rb
126
121
  - lib/ruby_skynet/ruby_skynet.rb
127
122
  - lib/ruby_skynet/server.rb
128
123
  - lib/ruby_skynet/service.rb
124
+ - lib/ruby_skynet/service_registry.rb
129
125
  - lib/ruby_skynet/version.rb
130
126
  - test.sh
131
127
  - test/base_test.rb
132
128
  - test/client_test.rb
133
- - test/doozer_client_test.rb
134
- - test/registry_test.rb
129
+ - test/service_registry_test.rb
135
130
  - test/service_test.rb
136
131
  homepage: https://github.com/ClarityServices/ruby_skynet
137
132
  licenses:
data/examples/e.rb DELETED
File without changes
@@ -1,209 +0,0 @@
1
- require 'ruby_skynet/doozer/msg.pb'
2
- require 'semantic_logger'
3
- require 'resilient_socket'
4
- require 'ruby_skynet/doozer/exceptions'
5
- require 'ruby_skynet/doozer/msg.pb'
6
-
7
- module RubySkynet
8
- module Doozer
9
- class Client
10
-
11
- include SemanticLogger::Loggable
12
-
13
- # Create a resilient client connection to a Doozer server
14
- def initialize(params={})
15
- # User configurable options
16
- params[:read_timeout] ||= 5
17
- params[:connect_timeout] ||= 3
18
- params[:connect_retry_interval] ||= 0.1
19
- params[:connect_retry_count] ||= 3
20
-
21
- # Server name and port where Doozer is running
22
- # Defaults to 127.0.0.1:8046
23
- params[:server] ||= '127.0.0.1:8046' unless params[:servers]
24
-
25
- # Disable buffering the send since it is a RPC call
26
- params[:buffered] = false
27
-
28
- logger.trace "Socket Connection parameters", params.dup
29
-
30
- # For each new connection
31
- params[:on_connect] = Proc.new do |socket|
32
- # Reset user_data on each connection
33
- socket.user_data = 0
34
- end
35
-
36
- @socket = ResilientSocket::TCPClient.new(params)
37
- end
38
-
39
- # Close this client connection to doozer
40
- def close
41
- @socket.close if @socket
42
- end
43
-
44
- # Returns the current Doozer revision
45
- def current_revision
46
- invoke(Request.new(:verb => Request::Verb::REV)).rev
47
- end
48
-
49
- # Set a value in Doozer
50
- # path: Path to the value to be set
51
- # value: Value to set
52
- # rev: Revision at which to set the value
53
- # If not supplied it will replace the latest version on the server
54
- #
55
- # Returns the new revision of the updated value
56
- #
57
- # It is recommended to set the revision so that multiple clients do not
58
- # attempt to update the value at the same time.
59
- # Setting the revision also allows the call to be retried automatically
60
- # in the event of a network failure
61
- def set(path, value, rev=-1)
62
- invoke(Request.new(:path => path, :value => value, :rev => rev, :verb => Request::Verb::SET), false).rev
63
- end
64
-
65
- # Sets the current value at the supplied path
66
- def []=(path,value)
67
- set(path, value)
68
- end
69
-
70
- # Return the value at the supplied path and revision
71
- def get(path, rev = nil)
72
- invoke(Request.new(:path => path, :rev => rev, :verb => Request::Verb::GET))
73
- end
74
-
75
- # Returns just the value at the supplied path, not the revision
76
- def [](path)
77
- get(path).value
78
- end
79
-
80
- # Deletes the file at path if rev is greater than or equal to the file's revision.
81
- # Returns nil when the file was removed
82
- # Raises an exception if an attempt to remove the file and its revision
83
- # is greater than that supplied
84
- def delete(path, rev=-1)
85
- invoke(Request.new(:path => path, :rev => rev, :verb => Request::Verb::DEL))
86
- nil
87
- end
88
-
89
- # Returns the directory in the supplied path
90
- # Use offset to get the next
91
- # returns nil if no further paths are available
92
- def directory(path, offset = 0, rev = nil)
93
- begin
94
- invoke(Request.new(:path => path, :rev => rev, :offset => offset, :verb => Request::Verb::GETDIR))
95
- rescue RubySkynet::Doozer::ResponseError => exc
96
- raise exc unless exc.message.include?('RANGE')
97
- nil
98
- end
99
- end
100
-
101
- def stat(path, rev = nil)
102
- invoke(Request.new(:path => path, :rev => rev, :verb => Request::Verb::STAT))
103
- end
104
-
105
- def access(secret)
106
- invoke(Request.new(:path => secret, :verb => Request::Verb::ACCESS))
107
- end
108
-
109
- # Returns every entry in the supplied path
110
- # path can also contain wildcard characters such as '*'
111
- # Example:
112
- # hosts = []
113
- # walk('/ctl/node/*/addr', current_revision).each do |node|
114
- # hosts << node.value unless hosts.include? node.value
115
- # end
116
- def walk(path, rev = nil, offset = 0)
117
- paths = []
118
- revision = rev || current_revision
119
- # Resume walk on network connection failure
120
- @socket.retry_on_connection_failure do
121
- while true
122
- send(Request.new(:path => path, :rev => revision , :offset => offset, :verb => Request::Verb::WALK))
123
- response = read
124
- if response.err_code
125
- break if response.err_code == Response::Err::RANGE
126
- else
127
- raise ResponseError.new("#{Response::Err.name_by_value(response.err_code)}: #{response.err_detail}") if response.err_code != 0
128
- end
129
- paths << response
130
- offset += 1
131
- end
132
- end
133
- paths
134
- end
135
-
136
- # Returns [Array] of hostname [String] with each string
137
- # representing another Doozer server that can be connected to
138
- def doozer_hosts
139
- hosts = []
140
- walk('/ctl/node/*/addr', current_revision).each do |node|
141
- hosts << node.value unless hosts.include? node.value
142
- end
143
- end
144
-
145
- # Wait for changes to the supplied path
146
- # Returns the next change to the supplied path
147
- def wait(path, rev=current_revision, timeout=-1)
148
- invoke(Request.new(:path => path, :rev => rev, :verb => Request::Verb::WAIT), true, timeout)
149
- end
150
-
151
- # Watch for any changes to the supplied path, calling the supplied block
152
- # for every change
153
- # Runs until an exception is thrown
154
- #
155
- # If a connection error occurs it will create a new connection to doozer
156
- # and resubmit the wait. I.e. Will continue from where it left off
157
- # without any noticeable effect to the supplied block
158
- def watch(path, rev=current_revision)
159
- loop do
160
- result = wait(path, rev, -1)
161
- yield result
162
- rev = result.rev + 1
163
- end
164
- end
165
-
166
- #####################
167
- #protected
168
-
169
- # Call the Doozer server
170
- #
171
- # When readonly ==> true the request is always retried on network failure
172
- # When readonly ==> false the request is retried on network failure
173
- # _only_ if a rev has been supplied
174
- #
175
- # When modifier is true
176
- def invoke(request, readonly=true, timeout=nil)
177
- retry_read = readonly || !request.rev.nil?
178
- response = nil
179
- @socket.retry_on_connection_failure do
180
- send(request)
181
- response = read(timeout) if retry_read
182
- end
183
- # Network error on read must be sent back to caller since we do not
184
- # know if the modification was made
185
- response = read(timeout) unless retry_read
186
- raise ResponseError.new("#{Response::Err.name_by_value(response.err_code)} (#{response.err_code}): #{response.err_detail}") if response.err_code != 0
187
- response
188
- end
189
-
190
- # Send the protobuf Request to Doozer
191
- def send(request)
192
- request.tag = 0
193
- data = request.serialize_to_string
194
- # An additional header is added to the request indicating the size of the request
195
- head = [data.length].pack("N")
196
- @socket.write(head+data)
197
- end
198
-
199
- # Read the protobuf Response from Doozer
200
- def read(timeout=nil)
201
- # First strip the additional header indicating the size of the subsequent response
202
- head = @socket.read(4,nil,timeout)
203
- length = head.unpack("N")[0]
204
- Response.new.parse_from_string(@socket.read(length))
205
- end
206
-
207
- end
208
- end
209
- end
@@ -1,5 +0,0 @@
1
- module RubySkynet
2
- module Doozer
3
- class ResponseError < ::RuntimeError; end
4
- end
5
- end
@@ -1,118 +0,0 @@
1
- ### Generated by rprotoc. DO NOT EDIT!
2
- ### <proto file: doozerd/server/msg.proto>
3
- # package server;
4
- #
5
- # // see doc/proto.md
6
- # message Request {
7
- # optional int32 tag = 1;
8
- #
9
- # enum Verb {
10
- # GET = 1;
11
- # SET = 2;
12
- # DEL = 3;
13
- # REV = 5;
14
- # WAIT = 6;
15
- # NOP = 7;
16
- # WALK = 9;
17
- # GETDIR = 14;
18
- # STAT = 16;
19
- # ACCESS = 99;
20
- # }
21
- # optional Verb verb = 2;
22
- #
23
- # optional string path = 4;
24
- # optional bytes value = 5;
25
- # optional int32 other_tag = 6;
26
- #
27
- # optional int32 offset = 7;
28
- #
29
- # optional int64 rev = 9;
30
- # }
31
- #
32
- # // see doc/proto.md
33
- # message Response {
34
- # optional int32 tag = 1;
35
- # optional int32 flags = 2;
36
- #
37
- # optional int64 rev = 3;
38
- # optional string path = 5;
39
- # optional bytes value = 6;
40
- # optional int32 len = 8;
41
- #
42
- # enum Err {
43
- # // don't use value 0
44
- # OTHER = 127;
45
- # TAG_IN_USE = 1;
46
- # UNKNOWN_VERB = 2;
47
- # READONLY = 3;
48
- # TOO_LATE = 4;
49
- # REV_MISMATCH = 5;
50
- # BAD_PATH = 6;
51
- # MISSING_ARG = 7;
52
- # RANGE = 8;
53
- # NOTDIR = 20;
54
- # ISDIR = 21;
55
- # NOENT = 22;
56
- # }
57
- # optional Err err_code = 100;
58
- # optional string err_detail = 101;
59
- # }
60
-
61
- require 'protobuf/message/message'
62
- require 'protobuf/message/enum'
63
- require 'protobuf/message/service'
64
- require 'protobuf/message/extend'
65
-
66
- module RubySkynet
67
- module Doozer
68
- class Request < ::Protobuf::Message
69
- defined_in __FILE__
70
- optional :int32, :tag, 1
71
- class Verb < ::Protobuf::Enum
72
- defined_in __FILE__
73
- GET = value(:GET, 1)
74
- SET = value(:SET, 2)
75
- DEL = value(:DEL, 3)
76
- REV = value(:REV, 5)
77
- WAIT = value(:WAIT, 6)
78
- NOP = value(:NOP, 7)
79
- WALK = value(:WALK, 9)
80
- GETDIR = value(:GETDIR, 14)
81
- STAT = value(:STAT, 16)
82
- ACCESS = value(:ACCESS, 99)
83
- end
84
- optional :Verb, :verb, 2
85
- optional :string, :path, 4
86
- optional :bytes, :value, 5
87
- optional :int32, :other_tag, 6
88
- optional :int32, :offset, 7
89
- optional :int64, :rev, 9
90
- end
91
- class Response < ::Protobuf::Message
92
- defined_in __FILE__
93
- optional :int32, :tag, 1
94
- optional :int32, :flags, 2
95
- optional :int64, :rev, 3
96
- optional :string, :path, 5
97
- optional :bytes, :value, 6
98
- optional :int32, :len, 8
99
- class Err < ::Protobuf::Enum
100
- defined_in __FILE__
101
- OTHER = value(:OTHER, 127)
102
- TAG_IN_USE = value(:TAG_IN_USE, 1)
103
- UNKNOWN_VERB = value(:UNKNOWN_VERB, 2)
104
- READONLY = value(:READONLY, 3)
105
- TOO_LATE = value(:TOO_LATE, 4)
106
- REV_MISMATCH = value(:REV_MISMATCH, 5)
107
- BAD_PATH = value(:BAD_PATH, 6)
108
- MISSING_ARG = value(:MISSING_ARG, 7)
109
- RANGE = value(:RANGE, 8)
110
- NOTDIR = value(:NOTDIR, 20)
111
- ISDIR = value(:ISDIR, 21)
112
- NOENT = value(:NOENT, 22)
113
- end
114
- optional :Err, :err_code, 100
115
- optional :string, :err_detail, 101
116
- end
117
- end
118
- end