fairway 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2b3057c6ab8a45805ace676a8d13f8775ca5b42b
4
- data.tar.gz: 0520d51ae3dc1aa63557d1aa253d62f1cf03b1e8
3
+ metadata.gz: 560fe83c9779d40b22fe2d5e093d3ad9310dd9ed
4
+ data.tar.gz: f1c2d3c7933944f75a0df7c987430a5a524193bc
5
5
  SHA512:
6
- metadata.gz: 6592bfbf636f74b6f9deb95c508d74464202b70fab905c8c293e393179c3904c88353aaba1b1fd8784c29c7e94abd4fb993f63d3447e4253f8c1cada4404fcbd
7
- data.tar.gz: b6d6099a051fdf43df55f8070ccfc8a0203e3463d2bfbb303ebecaf9e62c31a0c46417b7e80bf413e4f77a41fdaeef0442e9722586c8a807473df989ff45e3d7
6
+ metadata.gz: 3c20f8ce9420514cd5ca9c1b54382aa5a8ce0bdd9f7e9947981864edfb169c54d6557ee0eb6c0f323727406d059c9054885386e97d5199f45ded8d4bceaea58b
7
+ data.tar.gz: fb5e08076353e022fd4fbc9207d79ea566b014c3e789b056a8107a3bdf0cf2615c5d366a5fd577b66c18b621ecbfa3bd387178f08b47483e5fe9619c5a17c9b2
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fairway (0.2.1)
4
+ fairway (0.2.6)
5
5
  activesupport
6
6
  connection_pool
7
7
  redis
@@ -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 ||= pool { Redis::Namespace.new(@namespace, redis: raw_redis) }
81
+ @redis ||= redises
37
82
  end
38
83
 
39
84
  def scripts
40
85
  @scripts ||= begin
41
- Scripts.new(pool { raw_redis }, @namespace)
86
+ Scripts.new(raw_redises, @namespace)
42
87
  end
43
88
  end
44
89
 
45
90
  private
46
91
 
47
- def pool(&block)
48
- pool_size = @redis_options[:pool] || 1
49
- pool_timeout = @redis_options[:timeout] || 5
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(@redis_options)
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.with do |conn|
14
- each_queue do |queue|
15
- conn.llen(facet_key(queue))
16
- end.sum
17
- end
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
- redis.with do |conn|
12
- facet_names = unique_queues.map do |queue|
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.uniq
15
-
16
- facet_names.map do |name|
17
- Facet.new(self, name)
18
- end
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.with do |conn|
24
- conn.mget(unique_queues.map{|q| "#{q}:length" }).map(&:to_i).sum
25
- end
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
@@ -15,13 +15,13 @@ module Fairway
15
15
  end
16
16
 
17
17
  def register_queue(name, channel)
18
- redis.with do |conn|
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.with do |conn|
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
- redis.with do |conn|
39
- conn.evalsha(script_sha(method_name), [namespace], args)
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.with do |conn|
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
@@ -1,3 +1,3 @@
1
1
  module Fairway
2
- VERSION = "0.2.6"
2
+ VERSION = "0.2.7"
3
3
  end
@@ -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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fairway
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Allison