etcd-leader 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 67543b2534808d395ed9d5f60f85b857b2356cc7
4
+ data.tar.gz: 296c9be5db6395310b08218d9aaaabe3805f2788
5
+ SHA512:
6
+ metadata.gz: 318245162f3d9f73d97d32b1f71b2163776cb3687b1034e2a98f8a8f6182532de80da635fc608947210aa8a02c823bfa68fd56034ebe29b0221f27c43686a089
7
+ data.tar.gz: 21b3ef5a7604882ca875081e724ab26e7052611d3a1f715e1d40443a1b45b231c05c97b09ff028334ea50a5d042c0f01e5bf638188812d7ee8e18e04e82b66c1
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.10.4
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in etcd-leader.gemspec
4
+ gemspec
@@ -0,0 +1,36 @@
1
+ # Etcd::Leader
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/etcd/leader`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'etcd-leader'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install etcd-leader
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake false` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/etcd-leader.
36
+
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'etcd/leader/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "etcd-leader"
8
+ spec.version = Etcd::Leader.version
9
+ spec.authors = ["dhananjay.s"]
10
+ spec.email = ["dhananjay.s@endurance.com"]
11
+
12
+ spec.summary = %q{Simple drop in EtcD leader election implementation for Ruby}
13
+ spec.description = %q{Simple minimalistic library to provide reliable leadership election for your distributed application in Ruby using atomic in-order insertion backed by Etcd }
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ spec.bindir = "exe"
17
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency 'etcd'
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.10"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ end
@@ -0,0 +1,103 @@
1
+ require "etcd/leader/version"
2
+ require 'etcd'
3
+ require 'securerandom'
4
+
5
+ module Etcd
6
+ class Leader
7
+ attr_reader :started, :is_leader, :current_leader, :node_name
8
+ def initialize(service_key, opts={})
9
+ # Unique service keys are necessary for avoiding clashes between different services in the etcd cluster
10
+ @service_key = service_key
11
+ @etcd = opts[:etcd] || Etcd.client
12
+ @node_name = opts[:name] || SecureRandom.uuid
13
+ @ttl = opts[:ttl] || 10
14
+
15
+ # Local Threads of execution
16
+ @main_loop = nil
17
+ @refresh_loop = nil
18
+
19
+ # Some basic attributes
20
+ @started = false
21
+ @is_leader = false
22
+ @current_leader = nil
23
+ @membership_key = nil
24
+ @modified_index = nil
25
+ end
26
+
27
+ def start
28
+ return if @started
29
+ @started = true
30
+ setup
31
+ end
32
+
33
+ def stop
34
+ return if !@started
35
+ puts "Stopping #{@node_name}"
36
+ @started = false
37
+ @refresh_thread.kill
38
+ @main_loop.kill
39
+ @main_loop = nil
40
+ @refresh_thread = nil
41
+ @etcd.delete(@membership_key)
42
+ @membership_key = nil
43
+ @modified_index = nil
44
+ @is_leader = false
45
+ @current_leader = nil
46
+ end
47
+
48
+ def setup
49
+ res = @etcd.create_in_order(@service_key,value:@node_name,ttl:@ttl)
50
+ @membership_key = res.node.key
51
+ @modified_index = res.node.modified_index
52
+ @main_loop = Thread.new{ loop{check_leader}}
53
+ @refresh_thread = Thread.new{ refresh }
54
+ end
55
+
56
+ def on_new_leader(&block)
57
+ @on_new_leader = block
58
+ end
59
+
60
+ def handle_new_leader
61
+ @on_new_leader.call(@node_name, @is_leader, @current_leader) if @on_new_leader
62
+ end
63
+
64
+ def on_self_elected(&block)
65
+ @on_elected = block
66
+ self
67
+ end
68
+
69
+ def handle_self_elected
70
+ @on_elected.call(@node_name, @is_leader, @current_leader) if @on_elected
71
+ end
72
+
73
+ def check_leader
74
+ res = @etcd.get(@service_key,sorted:true)
75
+ nodes = res.node.children
76
+ if @current_leader != nodes.first.value
77
+ @current_leader = nodes.first.value
78
+ handle_new_leader
79
+ end
80
+ if @membership_key == nodes.first.key
81
+ @is_leader = true
82
+ handle_self_elected
83
+ res = @etcd.watch(@membership_key)
84
+ if res.node.value != @node_name
85
+ stop
86
+ start
87
+ end
88
+ else
89
+ index = nodes.index{|i| i.key == @membership_key}
90
+ @etcd.watch(nodes[index-1].key)
91
+ end
92
+ end
93
+
94
+ def refresh
95
+ loop do
96
+ sleep @ttl/2
97
+ res = @etcd.set(@membership_key, value:@node_name, ttl:@ttl, prevIndex:@modified_index)
98
+ @modified_index = res.node.modified_index
99
+ end
100
+ end
101
+ end
102
+ end
103
+
@@ -0,0 +1,7 @@
1
+ module Etcd
2
+ class Leader
3
+ def self.version
4
+ "0.1.0"
5
+ end
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: etcd-leader
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - dhananjay.s
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-08-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: etcd
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.10'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.10'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ description: 'Simple minimalistic library to provide reliable leadership election
56
+ for your distributed application in Ruby using atomic in-order insertion backed
57
+ by Etcd '
58
+ email:
59
+ - dhananjay.s@endurance.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".gitignore"
65
+ - ".travis.yml"
66
+ - Gemfile
67
+ - README.md
68
+ - Rakefile
69
+ - etcd-leader.gemspec
70
+ - lib/etcd/leader.rb
71
+ - lib/etcd/leader/version.rb
72
+ homepage:
73
+ licenses: []
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 2.4.8
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: Simple drop in EtcD leader election implementation for Ruby
95
+ test_files: []