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 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