redis-retry 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Matt Duncan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ redis-retry
2
+ ===========
3
+
4
+ Requires the redis gem.
5
+
6
+ Automatically retries all Redis calls if the Redis server is not available.
7
+
8
+ r = Redis::Retry.new(:tries => 3, :wait => 5, :redis => @r)
9
+
10
+ Redis::Retry will proxy all Redis calls. If a `Errno::ECONNREFUSED` error
11
+ occurs, the command will be retried the specified number of times, waiting the
12
+ specified number of seconds between tries. After all tries have been made
13
+ unsuccessfully, the `Errno::ECONNREFUSED` will be raised.
14
+
15
+ Useful to ensure that apps don't fail when Redis is unavailable for a short
16
+ amount of time.
17
+
18
+
19
+ Installation
20
+ ------------
21
+
22
+ $ gem install redis-retry
23
+
24
+
25
+ Author
26
+ ------
27
+
28
+ Matt Duncan
29
+ matt@mattduncan.org
@@ -0,0 +1,34 @@
1
+ require 'rake/testtask'
2
+
3
+ task :default => :test
4
+
5
+ desc "Runs unit tests"
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'test'
8
+ t.test_files = FileList['test/test_*.rb']
9
+ end
10
+
11
+ desc "Build a gem"
12
+ task :gem => [:gemspec, :build]
13
+
14
+ begin
15
+ require 'jeweler'
16
+ Jeweler::Tasks.new do |gemspec|
17
+ gemspec.name = "redis-retry"
18
+ gemspec.summary = "Auto-retries Redis commands."
19
+ gemspec.email = "matt@mattduncan.org"
20
+ gemspec.homepage = "http://github.com/mrduncan/redis-retry"
21
+ gemspec.authors = ["Matt Duncan"]
22
+ gemspec.version = '0.1.0'
23
+ gemspec.add_dependency 'redis'
24
+ gemspec.description = <<description
25
+ Adds a Redis::Retry class which can be used to proxy calls to Redis while
26
+ automatically retrying when a connection cannot be made. This is useful
27
+ to ensure that your applications don't fail if Redis is temporarily
28
+ unavailable.
29
+ description
30
+ end
31
+ rescue LoadError
32
+ warn "Jeweler not available. Install it with:"
33
+ warn "gem install jeweler"
34
+ end
@@ -0,0 +1,40 @@
1
+ require 'redis'
2
+
3
+ class Redis
4
+ class Retry
5
+ # The number of times a command will be retried if a connection cannot be
6
+ # made to Redis. If zero, retry forever.
7
+ attr_accessor :tries
8
+
9
+ # The number of seconds to wait before retrying a command.
10
+ attr_accessor :wait
11
+
12
+ def initialize(options = {})
13
+ @tries = options[:tries] || 3
14
+ @wait = options[:wait] || 2
15
+ @redis = options[:redis]
16
+ end
17
+
18
+ # Ruby defines a now deprecated type method so we need to override it here
19
+ # since it will never hit method_missing.
20
+ def type(key)
21
+ method_missing(:type, key)
22
+ end
23
+
24
+ def method_missing(command, *args, &block)
25
+ try = 1
26
+ while try <= @tries
27
+ begin
28
+ # Dispatch the command to Redis
29
+ return @redis.send(command, *args, &block)
30
+ rescue Errno::ECONNREFUSED
31
+ try += 1
32
+ sleep @wait
33
+ end
34
+ end
35
+
36
+ # Ran out of retries
37
+ raise Errno::ECONNREFUSED
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,47 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'test/unit'
3
+ require 'mocha'
4
+ require 'redis'
5
+ require 'redis/retry'
6
+
7
+ class TestRedisRetry < Test::Unit::TestCase
8
+ def setup
9
+ @r = Redis.new :db => 15
10
+ @redis = Redis::Retry.new(:tries => 10, :wait => 0, :redis => @r)
11
+ @redis.flushdb
12
+ end
13
+
14
+ def test_should_set_and_get_without_retries
15
+ @redis['foo'] = 'bar'
16
+ assert_equal 'bar', @redis['foo']
17
+ end
18
+
19
+ def test_should_retry_after_receiving_connection_refused
20
+ @r.stubs(:send).raises(Errno::ECONNREFUSED).then.returns(true)
21
+ assert @redis['foo']
22
+ end
23
+
24
+ def test_should_retry_as_many_times_as_possible
25
+ send = sequence('send')
26
+ @r.stubs(:send).raises(Errno::ECONNREFUSED).times(9).in_sequence(send)
27
+ @r.stubs(:send).returns(true).in_sequence(send)
28
+ assert @redis['foo']
29
+ end
30
+
31
+ def test_should_fail_if_retries_are_used_up
32
+ @r.stubs(:send).raises(Errno::ECONNREFUSED).times(10)
33
+ assert_raise(Errno::ECONNREFUSED) { @redis['foo'] }
34
+ end
35
+
36
+ def test_should_reset_tries_for_every_call
37
+ # Mocha doesn't seem to like the two #raises with the #returns between
38
+ # unless they are distinguished by expecting different input params
39
+ send = sequence('send')
40
+ @r.stubs(:send).with(:[], 'foo').raises(Errno::ECONNREFUSED).times(8).in_sequence(send)
41
+ @r.stubs(:send).with(:[], 'foo').returns(true).in_sequence(send)
42
+ @r.stubs(:send).with(:[], 'bar').raises(Errno::ECONNREFUSED).times(8).in_sequence(send)
43
+ @r.stubs(:send).with(:[], 'bar').returns(true).in_sequence(send)
44
+ assert @redis['foo']
45
+ assert @redis['bar']
46
+ end
47
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redis-retry
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Matt Duncan
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-15 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: redis
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ description: |
33
+ Adds a Redis::Retry class which can be used to proxy calls to Redis while
34
+ automatically retrying when a connection cannot be made. This is useful
35
+ to ensure that your applications don't fail if Redis is temporarily
36
+ unavailable.
37
+
38
+ email: matt@mattduncan.org
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files:
44
+ - LICENSE
45
+ - README.md
46
+ files:
47
+ - LICENSE
48
+ - README.md
49
+ - Rakefile
50
+ - lib/redis/retry.rb
51
+ - test/test_redis_retry.rb
52
+ has_rdoc: true
53
+ homepage: http://github.com/mrduncan/redis-retry
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options:
58
+ - --charset=UTF-8
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ requirements: []
76
+
77
+ rubyforge_project:
78
+ rubygems_version: 1.3.6
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: Auto-retries Redis commands.
82
+ test_files:
83
+ - test/test_redis_retry.rb