zoo-service-discovery 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 +15 -0
- data/README.md +30 -0
- data/lib/zoo-service-discovery.rb +2 -0
- data/lib/zoo_service/discovery.rb +45 -0
- data/lib/zoo_service/publication.rb +59 -0
- data/spec/features/complex_discovery_spec.rb +69 -0
- data/spec/features/discovery_spec.rb +40 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/support/zookeeper_runner.rb +36 -0
- metadata +52 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZmFlYTU1NDM4ODZkZThmMzllMWQxODVmM2I4ZmQ2YjEzYjc2NzEzYQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MDNlNGVhYmZhOGMxZjk4NWZmNmVlNzIxMWMyODcwN2JmZTZjNDUwMg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
Y2RjZTg3ZWNkMDBmYjc4M2Q4YjRiZTg0NzkzNGM1OGMxN2Y0OTY2ODViNDc3
|
10
|
+
ODUyYjI2YTViMDMwYzcyMTA0MzdhN2VlZDFlMmE0OTMxNGNmNTgyMmQxZDcw
|
11
|
+
ZWE4ZTgxYmJiNmMzOGEzN2Q3YWJjYWNjNzdiNjU0YzQxNzkwMDU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZmI4Nzc3MzBmNzdiZjg5OThkYTdhMjIwMjk3YmU2OTA3ZTlhNzczZDgzNDcy
|
14
|
+
MWZkYmVjMDNmMGU0YjE1NmY4YTRhNDE3YzAwZTZkMWJmNDlhN2NhNDliZGU5
|
15
|
+
ZWMwOGU0NzgxMTNkNjg2OWIyYTM1MzAwYzA0OTkzN2M3MjQzNmQ=
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# ZooKeeper Service Discovery
|
2
|
+
|
3
|
+
ZooKeeper service discovery gem.
|
4
|
+
|
5
|
+
You can use it to publish and discover well-known service URL's within your
|
6
|
+
application infrastructure.
|
7
|
+
|
8
|
+
## Service Publication by a Service Provider
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
require 'zoo-service-discovery'
|
12
|
+
|
13
|
+
ZooService::Publication.register_service('service_name', 'http://api.service.com/')
|
14
|
+
```
|
15
|
+
|
16
|
+
## Service Lookup by a Service Consumer
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
require 'zoo-service-discovery'
|
20
|
+
|
21
|
+
base_service_url = ZooService::Discovery.get_service_url('service_name')
|
22
|
+
```
|
23
|
+
|
24
|
+
## Specs
|
25
|
+
|
26
|
+
RSpecs were developed and ran on a Mac OS X machine. They require ZooKeeper to
|
27
|
+
be installed locally (e.g. via Brew) and be available in the path.
|
28
|
+
|
29
|
+
More details on how the Zookeeper instances are started and torn down are in
|
30
|
+
the ```zookeeper_runner.rb``` RSpec support file.
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'zk'
|
2
|
+
|
3
|
+
# Service discovery facilities namespace.
|
4
|
+
module ZooService
|
5
|
+
|
6
|
+
# Performs service discovery for a HTTP service consumer.
|
7
|
+
class Discovery
|
8
|
+
class << self
|
9
|
+
# :call-seq:
|
10
|
+
# get_service_url(name) => String
|
11
|
+
#
|
12
|
+
# Gets service URL by _name_.
|
13
|
+
#
|
14
|
+
# Returns service URL, if everything went OK, +nil+ otherwise.
|
15
|
+
def get_service_url(name)
|
16
|
+
get_published_urls(name).first
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
# Gets published URLs of _service_name_.
|
22
|
+
def get_published_urls(service_name)
|
23
|
+
service_path = "/services/#{service_name}"
|
24
|
+
publications = zk.children(service_path, ignore: :no_node) || [ ]
|
25
|
+
|
26
|
+
unless publications.empty?
|
27
|
+
zk.get("#{service_path}/#{publications.last}", ignore: :no_node)
|
28
|
+
else
|
29
|
+
[ ]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns a working instance of a ZooKeeper client.
|
34
|
+
def zk
|
35
|
+
if Thread.current[:service_discovery_zk_client]
|
36
|
+
return Thread.current[:service_discovery_zk_client]
|
37
|
+
end
|
38
|
+
|
39
|
+
Thread.current[:service_discovery_zk_client] ||= ZK.new(ENV['SERVICE_DISCOVERY_WELLKNOWN_ADDRESS'] || 'localhost:2181')
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'zk'
|
2
|
+
|
3
|
+
# Service discovery facilities namespace.
|
4
|
+
module ZooService
|
5
|
+
|
6
|
+
# Performs service publication for a HTTP service provider.
|
7
|
+
class Publication
|
8
|
+
class << self
|
9
|
+
# :call-seq:
|
10
|
+
# register_service(name, url) => Boolean
|
11
|
+
#
|
12
|
+
# Registers a well-known service with _name_ at _url_.
|
13
|
+
#
|
14
|
+
# Returns +true+, if everything went OK, +false+ otherwise.
|
15
|
+
def register_service(name, url)
|
16
|
+
registration_block = create_registration_block(name, url)
|
17
|
+
service_registration_blocks << registration_block
|
18
|
+
registration_block.(zk)
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
# Creates a lambda that once called registeres the service on the URL.
|
24
|
+
def create_registration_block(name, url)
|
25
|
+
-> zk {
|
26
|
+
service_path = "/services/#{name}"
|
27
|
+
zk.mkdir_p(service_path) unless zk.exists?(service_path)
|
28
|
+
zk.create("#{service_path}/node-", url, mode: :ephemeral_sequential)
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
# Stores the registration blocks that are rerun after reconnection to
|
33
|
+
# the ZooKeeper.
|
34
|
+
def service_registration_blocks
|
35
|
+
@service_registration_blocks ||= [ ]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns a working instance of a ZooKeeper client.
|
39
|
+
def zk
|
40
|
+
if Thread.current[:service_publication_zk_client]
|
41
|
+
return Thread.current[:service_publication_zk_client]
|
42
|
+
end
|
43
|
+
|
44
|
+
zk_client = ZK.new(ENV['SERVICE_DISCOVERY_WELLKNOWN_ADDRESS'] || 'localhost:2181') do |zk|
|
45
|
+
zk.on_connected do
|
46
|
+
# Rerun all the registrations upon reconnection
|
47
|
+
service_registration_blocks.each do |registration_block|
|
48
|
+
registration_block.(zk)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
Thread.current[:service_publication_zk_client] = zk_client
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Discovered service URL (registered in a separate process)" do
|
4
|
+
|
5
|
+
def kill_server_process
|
6
|
+
begin
|
7
|
+
Process.kill("HUP", server_process)
|
8
|
+
Process.wait(server_process)
|
9
|
+
rescue Errno::ESRCH
|
10
|
+
# ignore
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
before {
|
15
|
+
if Thread.current[:service_discovery_zk_client]
|
16
|
+
Thread.current[:service_discovery_zk_client].close
|
17
|
+
Thread.current[:service_discovery_zk_client] = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
if Thread.current[:service_publication_zk_client]
|
21
|
+
Thread.current[:service_publication_zk_client].close
|
22
|
+
Thread.current[:service_publication_zk_client] = nil
|
23
|
+
end
|
24
|
+
}
|
25
|
+
|
26
|
+
subject {
|
27
|
+
ZooService::Discovery.get_service_url(service)
|
28
|
+
}
|
29
|
+
|
30
|
+
let(:real_service_url) {
|
31
|
+
"http://sample.dev/"
|
32
|
+
}
|
33
|
+
|
34
|
+
let(:service) {
|
35
|
+
"service"
|
36
|
+
}
|
37
|
+
|
38
|
+
let!(:server_process) {
|
39
|
+
pid = fork do |variable|
|
40
|
+
ZooService::Publication.register_service(service, real_service_url)
|
41
|
+
sleep 1 while true
|
42
|
+
end
|
43
|
+
sleep 0.5
|
44
|
+
return pid
|
45
|
+
}
|
46
|
+
|
47
|
+
after do
|
48
|
+
kill_server_process
|
49
|
+
end
|
50
|
+
|
51
|
+
it { should == real_service_url }
|
52
|
+
|
53
|
+
it "should be nil after service owner termination" do
|
54
|
+
kill_server_process
|
55
|
+
sleep 30
|
56
|
+
should == nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it "retains value when ZooKeeper fails and restarts with an empty DB" do
|
60
|
+
should == real_service_url
|
61
|
+
|
62
|
+
ZookeeperRunner.clean
|
63
|
+
ZookeeperRunner.stop
|
64
|
+
ZookeeperRunner.start
|
65
|
+
|
66
|
+
should == real_service_url
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Discovered service URL" do
|
4
|
+
|
5
|
+
subject {
|
6
|
+
ZooService::Discovery.get_service_url(service)
|
7
|
+
}
|
8
|
+
|
9
|
+
let(:real_service_url) {
|
10
|
+
"http://sample.dev/"
|
11
|
+
}
|
12
|
+
|
13
|
+
context "when service is registered" do
|
14
|
+
|
15
|
+
let!(:service) {
|
16
|
+
ZooService::Publication.register_service("service", real_service_url)
|
17
|
+
"service"
|
18
|
+
}
|
19
|
+
|
20
|
+
it { should == real_service_url }
|
21
|
+
|
22
|
+
it "should be nil if ZooKeeper gets cleaned somehow" do
|
23
|
+
# eh, eh, negative case ;) just to be sure
|
24
|
+
ZookeeperRunner.clean # clean the ZooKeeper
|
25
|
+
should == nil # check that it cannot be discovered
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when service is not registered" do
|
31
|
+
|
32
|
+
let(:service) {
|
33
|
+
"service"
|
34
|
+
}
|
35
|
+
|
36
|
+
it { should == nil }
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require(:test)
|
3
|
+
|
4
|
+
require_relative "../lib/zoo_service/discovery"
|
5
|
+
require_relative "../lib/zoo_service/publication"
|
6
|
+
|
7
|
+
Dir[File.expand_path("../../spec/support/**/*.rb", __FILE__)].each { |f| require f }
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
11
|
+
config.run_all_when_everything_filtered = true
|
12
|
+
config.filter_run :focus
|
13
|
+
|
14
|
+
# Run specs in random order to surface order dependencies. If you find an
|
15
|
+
# order dependency and want to debug it, you can fix the order by providing
|
16
|
+
# the seed, which is printed after each run.
|
17
|
+
# --seed 1234
|
18
|
+
config.order = 'random'
|
19
|
+
|
20
|
+
config.before(:all) do
|
21
|
+
ZookeeperRunner.stop # ensure it's stopped
|
22
|
+
ZookeeperRunner.start
|
23
|
+
ZookeeperRunner.clean
|
24
|
+
end
|
25
|
+
|
26
|
+
config.after(:all) do
|
27
|
+
ZookeeperRunner.clean
|
28
|
+
ZookeeperRunner.stop
|
29
|
+
end
|
30
|
+
|
31
|
+
config.before do
|
32
|
+
ZookeeperRunner.clean
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class ZookeeperRunner
|
2
|
+
class << self
|
3
|
+
|
4
|
+
def start
|
5
|
+
system "zkServer start > /dev/null 2>&1"
|
6
|
+
wait_zookeeper_start
|
7
|
+
end
|
8
|
+
|
9
|
+
def stop
|
10
|
+
system "zkServer stop > /dev/null 2>&1"
|
11
|
+
wait_zookeeper_stop
|
12
|
+
end
|
13
|
+
|
14
|
+
def clean
|
15
|
+
ZK.open('localhost:2181') do |zk|
|
16
|
+
zk.rm_rf('/services')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def wait_zookeeper_start
|
23
|
+
sleep 1 while zookeeper_pid == 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def wait_zookeeper_stop
|
27
|
+
sleep 0.125 while zookeeper_pid > 0
|
28
|
+
end
|
29
|
+
|
30
|
+
def zookeeper_pid
|
31
|
+
`ps aux | grep zookeeper | grep java | grep -v grep | awk '{ print $2; }'`.to_i
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zoo-service-discovery
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Druzhinin <andrey.druginin@gmail.com>
|
8
|
+
- Ivan Kasatenko <sky@uniqsystems.ru>
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-09-23 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: ZooKeeper service discovery gem for your SOA environment.
|
15
|
+
email: support@uniqsystems.ru
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/zoo-service-discovery.rb
|
21
|
+
- lib/zoo_service/discovery.rb
|
22
|
+
- lib/zoo_service/publication.rb
|
23
|
+
- spec/features/complex_discovery_spec.rb
|
24
|
+
- spec/features/discovery_spec.rb
|
25
|
+
- spec/spec_helper.rb
|
26
|
+
- spec/support/zookeeper_runner.rb
|
27
|
+
- README.md
|
28
|
+
homepage: http://uniqsystems.ru/
|
29
|
+
licenses: []
|
30
|
+
metadata: {}
|
31
|
+
post_install_message:
|
32
|
+
rdoc_options: []
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
requirements: []
|
46
|
+
rubyforge_project:
|
47
|
+
rubygems_version: 2.0.7
|
48
|
+
signing_key:
|
49
|
+
specification_version: 4
|
50
|
+
summary: ZooKeeper service discovery gem
|
51
|
+
test_files: []
|
52
|
+
has_rdoc:
|