sidekiq-retries 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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sidekiq-retries.gemspec
4
+ gemspec
5
+
6
+ gem 'pry'
@@ -0,0 +1,27 @@
1
+ License
2
+ -------
3
+ Copyright (c) 2013, GovDelivery, Inc.
4
+
5
+ All rights reserved.
6
+
7
+ Redistribution and use in source and binary forms, with or without
8
+ modification, are permitted provided that the following conditions are met:
9
+ * Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+ * Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+ * Neither the name of GovDelivery nor the names of its contributors may be used
15
+ to endorse or promote products derived from this software without specific
16
+ prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,36 @@
1
+ # Sidekiq::Retries
2
+
3
+ This subclasses the stock Sidekiq retries middleware to give you some additional options to conditionally retry jobs
4
+ irrespective of whether retries are enabled for the job.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'sidekiq-retries'
11
+
12
+ ## Usage
13
+
14
+ class MyWorker
15
+ include Sidekiq::Worker
16
+ sidekiq_options retry: false # or retry: 25, or the default...
17
+
18
+ def perform
19
+ #force a retry even if retry: false using default retry options
20
+ raise Sidekiq::Retries::Retry.new(RuntimeError.new('whatever happened'))
21
+
22
+ #force a retry even if retry: false using a specific max_retries
23
+ raise Sidekiq::Retries::Retry.new(RuntimeError.new('whatever happened'), 10)
24
+
25
+ #if e.g. retries: true or retries: 10, skip it anyway
26
+ raise Sidekiq::Retries::Fail.new(RuntimeError.new('whatever happened'))
27
+ end
28
+ end
29
+
30
+ ## Contributing
31
+
32
+ 1. Fork it
33
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
34
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
35
+ 4. Push to the branch (`git push origin my-new-feature`)
36
+ 5. Create new Pull Request
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,15 @@
1
+ require "sidekiq/retries/version"
2
+ require 'sidekiq/retries/server/middleware'
3
+ require 'sidekiq/retries/errors'
4
+
5
+ Sidekiq.configure_server do |config|
6
+ require 'sidekiq/middleware/server/retry_jobs'
7
+ require 'sidekiq/retries/server/middleware'
8
+
9
+ stock_middleware = Sidekiq::Middleware::Server::RetryJobs
10
+
11
+ config.server_middleware do |chain|
12
+ chain.insert_before stock_middleware, Sidekiq::Retries::Server::Middleware
13
+ chain.remove stock_middleware
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ module Sidekiq
2
+ module Retries
3
+ class RetryError < StandardError
4
+ attr_accessor :cause
5
+
6
+ def initialize(cause, msg=nil)
7
+ super(msg)
8
+ self.cause=cause
9
+ end
10
+ end
11
+
12
+ class Retry < RetryError
13
+ attr_accessor :max_retries
14
+
15
+ def initialize(cause, max_retries=nil, msg=nil)
16
+ super(cause, msg)
17
+ self.max_retries = max_retries
18
+ end
19
+ end
20
+
21
+ class Fail < RetryError
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,73 @@
1
+ require 'celluloid'
2
+ require 'sidekiq/middleware/server/retry_jobs'
3
+
4
+ module Sidekiq
5
+ module Retries
6
+ module Server
7
+ class Middleware < Sidekiq::Middleware::Server::RetryJobs
8
+
9
+ def call(worker, msg, queue)
10
+ yield
11
+ rescue Sidekiq::Shutdown
12
+ # ignore, will be pushed back onto queue during hard_shutdown
13
+ raise
14
+ rescue Sidekiq::Retries::Retry => e
15
+ # force a retry (for workers that have retries disabled)
16
+ msg['retry'] ||= e.max_retries
17
+ attempt_retry(worker, msg, queue, e.cause)
18
+ raise e.cause
19
+ rescue Sidekiq::Retries::Fail => e
20
+ # don't retry this message (for workers that retry by default)
21
+ raise e.cause
22
+ rescue Exception => e
23
+ attempt_retry(worker, msg, queue, e) if msg['retry']
24
+ raise e
25
+ end
26
+
27
+ private
28
+
29
+ # This is the default Sidekiq 2.17.x retry logic
30
+ def attempt_retry(worker, msg, queue, e)
31
+ max_retry_attempts = retry_attempts_from(msg['retry'], @max_retries)
32
+
33
+ msg['queue'] = if msg['retry_queue']
34
+ msg['retry_queue']
35
+ else
36
+ queue
37
+ end
38
+ msg['error_message'] = e.message
39
+ msg['error_class'] = e.class.name
40
+ count = if msg['retry_count']
41
+ msg['retried_at'] = Time.now.utc
42
+ msg['retry_count'] += 1
43
+ else
44
+ msg['failed_at'] = Time.now.utc
45
+ msg['retry_count'] = 0
46
+ end
47
+
48
+ if msg['backtrace'] == true
49
+ msg['error_backtrace'] = e.backtrace
50
+ elsif msg['backtrace'] == false
51
+ # do nothing
52
+ elsif msg['backtrace'].to_i != 0
53
+ msg['error_backtrace'] = e.backtrace[0..msg['backtrace'].to_i]
54
+ end
55
+
56
+ if count < max_retry_attempts
57
+ delay = delay_for(worker, count)
58
+ logger.debug { "Failure! Retry #{count} in #{delay} seconds" }
59
+ retry_at = Time.now.to_f + delay
60
+ payload = Sidekiq.dump_json(msg)
61
+ Sidekiq.redis do |conn|
62
+ conn.zadd('retry', retry_at.to_s, payload)
63
+ end
64
+ else
65
+ # Goodbye dear message, you (re)tried your best I'm sure.
66
+ retries_exhausted(worker, msg)
67
+ end
68
+ end
69
+
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,5 @@
1
+ module Sidekiq
2
+ module Retries
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sidekiq/retries/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sidekiq-retries"
8
+ spec.version = Sidekiq::Retries::VERSION
9
+ spec.authors = ["Benjamin Ortega"]
10
+ spec.email = ["ben.ortega@gmail.com"]
11
+ spec.description = %q{Enhanced retry logic for Sidekiq workers}
12
+ spec.summary = %q{Enhanced retry logic for Sidekiq workers}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_dependency 'sidekiq', '~>2.17'
25
+ spec.add_development_dependency 'rake'
26
+ spec.add_development_dependency 'rspec'
27
+ spec.add_development_dependency 'rspec-mocks'
28
+ spec.add_development_dependency 'activesupport', '~> 3'
29
+ spec.add_development_dependency 'simplecov'
30
+ spec.add_development_dependency 'rspec-sidekiq'
31
+ end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ module Sidekiq
4
+ module Retries
5
+ module Server
6
+ class RetryWorker
7
+ include Sidekiq::Worker
8
+ end
9
+
10
+ describe Middleware do
11
+ let (:handler) { Sidekiq::Retries::Server::Middleware.new }
12
+ let (:queue) { 'default' }
13
+ let (:errmsg) { 'oh man what did you do' }
14
+
15
+ before do
16
+ Sidekiq::RetrySet.new.clear
17
+ end
18
+
19
+ context 'a worker without retry' do
20
+ it 'should retry anyway if we raise a Sidekiq::Retries::Retry' do
21
+ args = {'class' => 'Bob',
22
+ 'args' => [1],
23
+ 'retry' => false}
24
+ expect {
25
+ handler.call(RetryWorker, args, queue) do
26
+ raise Sidekiq::Retries::Retry.new(RuntimeError.new(errmsg), 10)
27
+ end
28
+ }.to raise_error(RuntimeError, errmsg)
29
+ expect(Sidekiq::RetrySet.new.size).to eq(1)
30
+ end
31
+
32
+ end
33
+
34
+ context 'a worker with retry' do
35
+ it 'should not retry if we raise a Sidekiq::Retries::Fail' do
36
+ args = {'class' => 'Bob',
37
+ 'args' => [1],
38
+ 'retry' => 2}
39
+ expect {
40
+ handler.call(RetryWorker, args, queue) do
41
+ raise Sidekiq::Retries::Fail.new(RuntimeError.new(errmsg))
42
+ end
43
+ }.to raise_error(RuntimeError, errmsg)
44
+
45
+ expect(Sidekiq::RetrySet.new.size).to eq(0)
46
+ end
47
+ end
48
+
49
+ end
50
+ end
51
+ end
52
+ end
metadata ADDED
@@ -0,0 +1,208 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sidekiq-retries
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Benjamin Ortega
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-02-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: sidekiq
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.17'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.17'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: rspec-mocks
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: activesupport
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: '3'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: '3'
126
+ - !ruby/object:Gem::Dependency
127
+ name: simplecov
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: rspec-sidekiq
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ description: Enhanced retry logic for Sidekiq workers
159
+ email:
160
+ - ben.ortega@gmail.com
161
+ executables: []
162
+ extensions: []
163
+ extra_rdoc_files: []
164
+ files:
165
+ - .gitignore
166
+ - Gemfile
167
+ - LICENSE.txt
168
+ - README.md
169
+ - Rakefile
170
+ - lib/sidekiq/retries.rb
171
+ - lib/sidekiq/retries/errors.rb
172
+ - lib/sidekiq/retries/server/middleware.rb
173
+ - lib/sidekiq/retries/version.rb
174
+ - sidekiq-retries.gemspec
175
+ - spec/lib/sidekiq/retries/server/middleware_spec.rb
176
+ homepage: ''
177
+ licenses:
178
+ - MIT
179
+ post_install_message:
180
+ rdoc_options: []
181
+ require_paths:
182
+ - lib
183
+ required_ruby_version: !ruby/object:Gem::Requirement
184
+ none: false
185
+ requirements:
186
+ - - ! '>='
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ segments:
190
+ - 0
191
+ hash: -4325984513531570110
192
+ required_rubygems_version: !ruby/object:Gem::Requirement
193
+ none: false
194
+ requirements:
195
+ - - ! '>='
196
+ - !ruby/object:Gem::Version
197
+ version: '0'
198
+ segments:
199
+ - 0
200
+ hash: -4325984513531570110
201
+ requirements: []
202
+ rubyforge_project:
203
+ rubygems_version: 1.8.23
204
+ signing_key:
205
+ specification_version: 3
206
+ summary: Enhanced retry logic for Sidekiq workers
207
+ test_files:
208
+ - spec/lib/sidekiq/retries/server/middleware_spec.rb