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 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,2 @@
1
+ require_relative 'zoo_service/discovery'
2
+ require_relative 'zoo_service/publication'
@@ -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
@@ -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: