fairway 0.2.6 → 0.2.7
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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/fairway/config.rb +77 -10
- data/lib/fairway/facet.rb +7 -5
- data/lib/fairway/queue.rb +14 -10
- data/lib/fairway/scripts.rb +32 -5
- data/lib/fairway/version.rb +1 -1
- data/spec/lib/fairway/config_spec.rb +53 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 560fe83c9779d40b22fe2d5e093d3ad9310dd9ed
|
4
|
+
data.tar.gz: f1c2d3c7933944f75a0df7c987430a5a524193bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c20f8ce9420514cd5ca9c1b54382aa5a8ce0bdd9f7e9947981864edfb169c54d6557ee0eb6c0f323727406d059c9054885386e97d5199f45ded8d4bceaea58b
|
7
|
+
data.tar.gz: fb5e08076353e022fd4fbc9207d79ea566b014c3e789b056a8107a3bdf0cf2615c5d366a5fd577b66c18b621ecbfa3bd387178f08b47483e5fe9619c5a17c9b2
|
data/Gemfile.lock
CHANGED
data/lib/fairway/config.rb
CHANGED
@@ -1,15 +1,60 @@
|
|
1
1
|
module Fairway
|
2
|
+
class RandomDistribution
|
3
|
+
class CannotConnect < RuntimeError; end
|
4
|
+
|
5
|
+
EXCEPTIONS = [
|
6
|
+
Redis::CannotConnectError,
|
7
|
+
Errno::ETIMEDOUT,
|
8
|
+
Errno::EHOSTUNREACH
|
9
|
+
]
|
10
|
+
|
11
|
+
attr_reader :pools
|
12
|
+
|
13
|
+
def initialize(pools)
|
14
|
+
@pools = pools
|
15
|
+
end
|
16
|
+
|
17
|
+
def with(&block)
|
18
|
+
valid_pools = @pools
|
19
|
+
|
20
|
+
while valid_pools.any?
|
21
|
+
pool = valid_pools.sample
|
22
|
+
|
23
|
+
pool.with do |conn|
|
24
|
+
begin
|
25
|
+
return yield(conn)
|
26
|
+
rescue *EXCEPTIONS
|
27
|
+
valid_pools -= [pool]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
raise CannotConnect.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def with_each(&block)
|
36
|
+
@pools.shuffle.each do |pool|
|
37
|
+
pool.with do |conn|
|
38
|
+
begin
|
39
|
+
yield(conn)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
2
46
|
class Config
|
3
47
|
attr_accessor :namespace
|
4
|
-
attr_reader :defined_queues, :redis_options
|
48
|
+
attr_reader :defined_queues, :redis_options, :distribute
|
5
49
|
|
6
50
|
DEFAULT_FACET = "default"
|
7
51
|
|
8
52
|
QueueDefinition = Struct.new(:name, :channel)
|
9
53
|
|
10
54
|
def initialize
|
11
|
-
@redis_options =
|
55
|
+
@redis_options = []
|
12
56
|
@namespace = nil
|
57
|
+
@distribute = RandomDistribution
|
13
58
|
@facet = lambda { |message| DEFAULT_FACET }
|
14
59
|
@defined_queues = []
|
15
60
|
|
@@ -29,32 +74,54 @@ module Fairway
|
|
29
74
|
end
|
30
75
|
|
31
76
|
def redis=(options)
|
32
|
-
@redis_options = options
|
77
|
+
@redis_options = [options].flatten
|
33
78
|
end
|
34
79
|
|
35
80
|
def redis
|
36
|
-
@redis ||=
|
81
|
+
@redis ||= redises
|
37
82
|
end
|
38
83
|
|
39
84
|
def scripts
|
40
85
|
@scripts ||= begin
|
41
|
-
Scripts.new(
|
86
|
+
Scripts.new(raw_redises, @namespace)
|
42
87
|
end
|
43
88
|
end
|
44
89
|
|
45
90
|
private
|
46
91
|
|
47
|
-
def
|
48
|
-
|
49
|
-
|
92
|
+
def redises
|
93
|
+
@redises ||= begin
|
94
|
+
@redis_options << {} if @redis_options.empty?
|
95
|
+
pools = @redis_options.map do |options|
|
96
|
+
pool(options) { Redis::Namespace.new(@namespace, redis: raw_redis(options)) }
|
97
|
+
end
|
98
|
+
|
99
|
+
@distribute.new(pools)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def raw_redises
|
104
|
+
@raw_redises ||= begin
|
105
|
+
@redis_options << {} if @redis_options.empty?
|
106
|
+
pools = @redis_options.map do |options|
|
107
|
+
pool(options) { raw_redis(options) }
|
108
|
+
end
|
109
|
+
|
110
|
+
@distribute.new(pools)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def pool(options, &block)
|
115
|
+
pool_size = options[:pool] || 1
|
116
|
+
pool_timeout = options[:timeout] || 5
|
50
117
|
|
51
118
|
ConnectionPool.new(size: pool_size, timeout: pool_timeout) do
|
52
119
|
yield
|
53
120
|
end
|
54
121
|
end
|
55
122
|
|
56
|
-
def raw_redis
|
57
|
-
Redis.new(
|
123
|
+
def raw_redis(options)
|
124
|
+
Redis.new(options)
|
58
125
|
end
|
59
126
|
end
|
60
127
|
end
|
data/lib/fairway/facet.rb
CHANGED
@@ -10,11 +10,13 @@ module Fairway
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def length
|
13
|
-
redis.
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
redis.pools.map do |pool|
|
14
|
+
pool.with do |conn|
|
15
|
+
each_queue do |queue|
|
16
|
+
conn.llen(facet_key(queue))
|
17
|
+
end.sum
|
18
|
+
end
|
19
|
+
end.sum
|
18
20
|
end
|
19
21
|
|
20
22
|
def priority
|
data/lib/fairway/queue.rb
CHANGED
@@ -8,21 +8,25 @@ module Fairway
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def active_facets
|
11
|
-
|
12
|
-
|
11
|
+
facet_names = []
|
12
|
+
|
13
|
+
redis.with_each do |conn|
|
14
|
+
facet_names += unique_queues.map do |queue|
|
13
15
|
conn.smembers("#{queue}:active_facets")
|
14
|
-
end.flatten
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
end.flatten
|
17
|
+
end
|
18
|
+
|
19
|
+
facet_names.uniq.map do |name|
|
20
|
+
Facet.new(self, name)
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
22
24
|
def length
|
23
|
-
redis.
|
24
|
-
|
25
|
-
|
25
|
+
redis.pools.map do |pool|
|
26
|
+
pool.with do |conn|
|
27
|
+
conn.mget(unique_queues.map{|q| "#{q}:length" }).map(&:to_i).sum
|
28
|
+
end
|
29
|
+
end.sum
|
26
30
|
end
|
27
31
|
|
28
32
|
def peek
|
data/lib/fairway/scripts.rb
CHANGED
@@ -15,13 +15,13 @@ module Fairway
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def register_queue(name, channel)
|
18
|
-
redis.
|
18
|
+
redis.with_each do |conn|
|
19
19
|
conn.hset(registered_queues_key, name, channel)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
def unregister_queue(name)
|
24
|
-
redis.
|
24
|
+
redis.with_each do |conn|
|
25
25
|
conn.hdel(registered_queues_key, name)
|
26
26
|
end
|
27
27
|
end
|
@@ -35,12 +35,22 @@ module Fairway
|
|
35
35
|
def method_missing(method_name, *args)
|
36
36
|
loaded = false
|
37
37
|
|
38
|
-
|
39
|
-
|
38
|
+
if multi?(method_name)
|
39
|
+
redis.with_each do |conn|
|
40
|
+
conn.evalsha(script_sha(method_name), [namespace], args)
|
41
|
+
end
|
42
|
+
elsif first?(method_name)
|
43
|
+
first_pool do |conn|
|
44
|
+
conn.evalsha(script_sha(method_name), [namespace], args)
|
45
|
+
end
|
46
|
+
else
|
47
|
+
redis.with do |conn|
|
48
|
+
conn.evalsha(script_sha(method_name), [namespace], args)
|
49
|
+
end
|
40
50
|
end
|
41
51
|
rescue Redis::CommandError => ex
|
42
52
|
if ex.message.include?("NOSCRIPT") && !loaded
|
43
|
-
redis.
|
53
|
+
redis.with_each do |conn|
|
44
54
|
conn.script(:load, script_source(method_name))
|
45
55
|
end
|
46
56
|
|
@@ -53,6 +63,23 @@ module Fairway
|
|
53
63
|
|
54
64
|
private
|
55
65
|
|
66
|
+
def first?(script)
|
67
|
+
["fairway_pull", "fairway_peek"].include?(script.to_s)
|
68
|
+
end
|
69
|
+
|
70
|
+
def multi?(script)
|
71
|
+
["fairway_priority", "fairway_destroy"].include?(script.to_s)
|
72
|
+
end
|
73
|
+
|
74
|
+
def first_pool(&block)
|
75
|
+
redis.with_each do |conn|
|
76
|
+
val = yield(conn)
|
77
|
+
return val if val
|
78
|
+
end
|
79
|
+
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
|
56
83
|
def registered_queues_key
|
57
84
|
"#{namespace}registered_queues"
|
58
85
|
end
|
data/lib/fairway/version.rb
CHANGED
@@ -29,19 +29,70 @@ module Fairway
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
it "allows multiple redis config" do
|
33
|
+
config = Config.new do |config|
|
34
|
+
config.redis = [
|
35
|
+
{ host: "127.0.0.1", port: 6379 },
|
36
|
+
{ host: "127.0.0.1", port: 6380 }
|
37
|
+
]
|
38
|
+
end
|
39
|
+
|
40
|
+
config.redis.pools.length.should == 2
|
41
|
+
end
|
42
|
+
|
43
|
+
it "distributes requests randomly between multiple redis's" do
|
44
|
+
config = Config.new do |config|
|
45
|
+
config.redis = [
|
46
|
+
{ host: "127.0.0.1", port: 6379 },
|
47
|
+
{ host: "127.0.0.1", port: 6380 }
|
48
|
+
]
|
49
|
+
end
|
50
|
+
|
51
|
+
ports = []
|
52
|
+
|
53
|
+
20.times do
|
54
|
+
config.redis.with do |conn|
|
55
|
+
ports << conn.info["tcp_port"]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
ports.uniq.sort.should == ["6379", "6380"]
|
60
|
+
end
|
61
|
+
|
62
|
+
it "doesn't lose requests if one redis is down" do
|
63
|
+
config = Config.new do |config|
|
64
|
+
config.redis = [
|
65
|
+
{ host: "127.0.0.1", port: 6379 },
|
66
|
+
{ host: "127.0.0.1", port: 6380 },
|
67
|
+
{ host: "127.0.0.1", port: 9999 }
|
68
|
+
]
|
69
|
+
end
|
70
|
+
|
71
|
+
ports = []
|
72
|
+
|
73
|
+
20.times do
|
74
|
+
config.redis.with do |conn|
|
75
|
+
ports << conn.info["tcp_port"]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
ports.length.should == 20
|
80
|
+
ports.uniq.sort.should == ["6379", "6380"]
|
81
|
+
end
|
82
|
+
|
32
83
|
it "allows setting of connection pooling" do
|
33
84
|
config = Config.new do |config|
|
34
85
|
config.redis = { pool: 10 }
|
35
86
|
end
|
36
87
|
|
37
|
-
config.redis.instance_variable_get("@size").should == 10
|
88
|
+
config.redis.pools.first.instance_variable_get("@size").should == 10
|
38
89
|
end
|
39
90
|
|
40
91
|
it "defaults to pool of 1" do
|
41
92
|
config = Config.new do |config|
|
42
93
|
end
|
43
94
|
|
44
|
-
config.redis.instance_variable_get("@size").should == 1
|
95
|
+
config.redis.pools.first.instance_variable_get("@size").should == 1
|
45
96
|
end
|
46
97
|
|
47
98
|
it "allows setting of redis namespace" do
|