balancir 0.0.1
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.
- data/.gitignore +17 -0
- data/.travis.yml +13 -0
- data/Gemfile +5 -0
- data/Guardfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +45 -0
- data/Rakefile +1 -0
- data/balancir.gemspec +29 -0
- data/lib/balancir.rb +4 -0
- data/lib/balancir/connector.rb +14 -0
- data/lib/balancir/distributor.rb +20 -0
- data/lib/balancir/version.rb +3 -0
- data/spec/lib/balancir/connector_spec.rb +17 -0
- data/spec/lib/balancir/distributor_spec.rb +72 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/fake_broken_service.ru +9 -0
- data/spec/support/fake_working_service.ru +9 -0
- metadata +182 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
|
2
|
+
guard 'rspec', :cli => "--color --format nested" do
|
3
|
+
watch(%r{^spec/(.+)_spec\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
4
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
5
|
+
watch(%r{^spec/support/*}) { 'spec' }
|
6
|
+
watch('spec/spec_helper.rb') { "spec" }
|
7
|
+
end
|
8
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Michael Brodhead
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# Balancir
|
2
|
+
|
3
|
+
Balancir is a client-side HTTP load balancer.
|
4
|
+
|
5
|
+
[](https://codeclimate.com/github/mkb/balancir)
|
6
|
+
[](https://travis-ci.org/mkb/balancir)
|
7
|
+
[](https://gemnasium.com/mkb/balancir)
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'balancir'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install balancir
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Come up with a name.
|
26
|
+
|
27
|
+
## Running the tests
|
28
|
+
|
29
|
+
bundle
|
30
|
+
bundle exec guard
|
31
|
+
# Hack away in another window. Guard will re-run tests as needed.
|
32
|
+
|
33
|
+
Or alternately:
|
34
|
+
|
35
|
+
bundle
|
36
|
+
bundle exec rspec
|
37
|
+
# Lament that you are not using Guard.
|
38
|
+
|
39
|
+
## Contributing
|
40
|
+
|
41
|
+
1. Fork it
|
42
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
43
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
44
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
45
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/balancir.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'balancir/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "balancir"
|
8
|
+
gem.version = Balancir::VERSION
|
9
|
+
gem.authors = ["Michael Brodhead", "Blaine Carlson"]
|
10
|
+
gem.email = ["mkb@orthogonal.org", "blaineosiris@comcast.net"]
|
11
|
+
gem.description = %q{A client side HTTP load balancer.}
|
12
|
+
gem.summary = %q{Allocate load between multiple instances of an HTTP service. } +
|
13
|
+
%q{Remove non-functioning servers from rotation and add them back when they become available.}
|
14
|
+
gem.homepage = "https://github.com/mkb/balancir"
|
15
|
+
|
16
|
+
gem.files = `git ls-files`.split($/)
|
17
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
|
+
gem.require_paths = ['lib']
|
20
|
+
|
21
|
+
gem.add_dependency('excon')
|
22
|
+
|
23
|
+
gem.add_development_dependency('rspec')
|
24
|
+
gem.add_development_dependency('guard')
|
25
|
+
gem.add_development_dependency('guard-rspec')
|
26
|
+
gem.add_development_dependency('travis-lint')
|
27
|
+
gem.add_development_dependency('sinatra')
|
28
|
+
gem.add_development_dependency('realweb')
|
29
|
+
end
|
data/lib/balancir.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module Balancir
|
2
|
+
# Represents a connection to a particular server
|
3
|
+
class Connector
|
4
|
+
attr_accessor :connection, :random, :recent_errors
|
5
|
+
|
6
|
+
def clear_errors
|
7
|
+
@recent_errors = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def record_error
|
11
|
+
@recent_errors << true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Balancir
|
2
|
+
# Accepts requests and distributes them between connectors.
|
3
|
+
class Distributor
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@connectors = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_connector(connector, weight)
|
10
|
+
@connectors << connector
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(path)
|
14
|
+
response = @connectors.first.get(path)
|
15
|
+
if (500..599).include? response.status
|
16
|
+
@connectors.first.record_error
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'realweb'
|
3
|
+
require 'balancir/connector'
|
4
|
+
|
5
|
+
describe Balancir::Connector do
|
6
|
+
# before :all do
|
7
|
+
# fake_server = File.expand_path('./spec/support/fake_working_service.ru')
|
8
|
+
# @server = RealWeb.start_server_in_thread(fake_server)
|
9
|
+
# end
|
10
|
+
|
11
|
+
# after :all do
|
12
|
+
# @server.stop
|
13
|
+
# end
|
14
|
+
|
15
|
+
pending 'error recording'
|
16
|
+
# need to support HMAC
|
17
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'balancir/distributor'
|
3
|
+
require 'balancir/connector'
|
4
|
+
|
5
|
+
describe Balancir::Distributor do
|
6
|
+
SOME_PATH = '/stuff/and/things'
|
7
|
+
ERROR_STATUSES = (500..511).to_a + [598, 599]
|
8
|
+
|
9
|
+
context 'with a single connector' do
|
10
|
+
before do
|
11
|
+
@connector = Balancir::Connector.new
|
12
|
+
@distributor = Balancir::Distributor.new
|
13
|
+
@distributor.add_connector(@connector, 100)
|
14
|
+
@response = double(:status => 200)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'message passing' do
|
18
|
+
it 'passes on calls to #get' do
|
19
|
+
@connector.should_receive(:get).and_return(@response)
|
20
|
+
@distributor.get(SOME_PATH)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'passes on calls to #post'
|
24
|
+
it 'passes on calls to #put'
|
25
|
+
it 'passes on calls to #delete'
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'error detection' do
|
29
|
+
it 'counts 500s as errors' do
|
30
|
+
ERROR_STATUSES.each do |status|
|
31
|
+
@connector.clear_errors
|
32
|
+
response = double(:status => status)
|
33
|
+
@connector.stub(:get).and_return(response)
|
34
|
+
@distributor.get(SOME_PATH)
|
35
|
+
@connector.recent_errors.count.should eq 1
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
pending "more error detection" do
|
40
|
+
it 'does not count 404 or 410 as errors'
|
41
|
+
it 'counts other 400s as errors'
|
42
|
+
it 'counts 700s as errors'
|
43
|
+
|
44
|
+
it 'counts Errno::ECONNRESET as an error'
|
45
|
+
it 'counts Errno::ETIMEDOUT as an error'
|
46
|
+
it 'counts Errno::ECONNREFUSED as an error'
|
47
|
+
it 'counts Errno::EHOSTUNREACH as an error'
|
48
|
+
it 'counts Errno::EAFNOSUPPORT as an error'
|
49
|
+
|
50
|
+
it "disables after enough errors"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
pending 'with a single, failed connector' do
|
56
|
+
it 'raises Balancir::NoConnectorsAvailable when called'
|
57
|
+
it 'tests the failed connector'
|
58
|
+
it 'reenables the failed connecor when it comes back'
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'with two well-behaved connectors' do
|
62
|
+
it 'distributes calls between them'
|
63
|
+
end
|
64
|
+
|
65
|
+
pending 'with two connectors, one well-behaved, one not' do
|
66
|
+
it 'tolerates occasional errors'
|
67
|
+
it 'disables a failing connector'
|
68
|
+
it 're-enables a failed connector which resumes working'
|
69
|
+
end
|
70
|
+
|
71
|
+
# what about notifications?
|
72
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: balancir
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Michael Brodhead
|
9
|
+
- Blaine Carlson
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2013-02-13 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: excon
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: rspec
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: guard
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: guard-rspec
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: travis-lint
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
type: :development
|
88
|
+
prerelease: false
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: sinatra
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: realweb
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ! '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
description: A client side HTTP load balancer.
|
128
|
+
email:
|
129
|
+
- mkb@orthogonal.org
|
130
|
+
- blaineosiris@comcast.net
|
131
|
+
executables: []
|
132
|
+
extensions: []
|
133
|
+
extra_rdoc_files: []
|
134
|
+
files:
|
135
|
+
- .gitignore
|
136
|
+
- .travis.yml
|
137
|
+
- Gemfile
|
138
|
+
- Guardfile
|
139
|
+
- LICENSE.txt
|
140
|
+
- README.md
|
141
|
+
- Rakefile
|
142
|
+
- balancir.gemspec
|
143
|
+
- lib/balancir.rb
|
144
|
+
- lib/balancir/connector.rb
|
145
|
+
- lib/balancir/distributor.rb
|
146
|
+
- lib/balancir/version.rb
|
147
|
+
- spec/lib/balancir/connector_spec.rb
|
148
|
+
- spec/lib/balancir/distributor_spec.rb
|
149
|
+
- spec/spec_helper.rb
|
150
|
+
- spec/support/fake_broken_service.ru
|
151
|
+
- spec/support/fake_working_service.ru
|
152
|
+
homepage: https://github.com/mkb/balancir
|
153
|
+
licenses: []
|
154
|
+
post_install_message:
|
155
|
+
rdoc_options: []
|
156
|
+
require_paths:
|
157
|
+
- lib
|
158
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
159
|
+
none: false
|
160
|
+
requirements:
|
161
|
+
- - ! '>='
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '0'
|
164
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
165
|
+
none: false
|
166
|
+
requirements:
|
167
|
+
- - ! '>='
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: '0'
|
170
|
+
requirements: []
|
171
|
+
rubyforge_project:
|
172
|
+
rubygems_version: 1.8.24
|
173
|
+
signing_key:
|
174
|
+
specification_version: 3
|
175
|
+
summary: Allocate load between multiple instances of an HTTP service. Remove non-functioning
|
176
|
+
servers from rotation and add them back when they become available.
|
177
|
+
test_files:
|
178
|
+
- spec/lib/balancir/connector_spec.rb
|
179
|
+
- spec/lib/balancir/distributor_spec.rb
|
180
|
+
- spec/spec_helper.rb
|
181
|
+
- spec/support/fake_broken_service.ru
|
182
|
+
- spec/support/fake_working_service.ru
|