sidekiq_unique_retries 0.1.0
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 +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +9 -0
- data/Gemfile +5 -0
- data/README.md +31 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/sidekiq_unique_retries.rb +51 -0
- data/lib/sidekiq_unique_retries/adapters/sidekiq_unique_jobs.rb +22 -0
- data/lib/sidekiq_unique_retries/extensions/api.rb +35 -0
- data/lib/sidekiq_unique_retries/extensions/job_retry.rb +27 -0
- data/lib/sidekiq_unique_retries/lock.rb +52 -0
- data/sidekiq_unique_retries.gemspec +27 -0
- metadata +115 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6577679bf6a5b58b52e3e632538c8facc8508423
|
4
|
+
data.tar.gz: b0a56f52bca88b9dd8970284575dbb803521a9ed
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e0886eb08c1f1de23a4afaff414ef409e688305e264ad78a62855476ce0f36e996b6ed064ecdeae4f969818f2aba4f4ee65da5280d1cd0458946f2c93b595af5
|
7
|
+
data.tar.gz: c47f7c0a862c39a336480c1bf86626eeef319749f009a6bed789174f4a5bd0b1adb9fe9303f7c311c84d29064cd9af331f65a9e11efe9c2646dda12c04556fbe
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Unique Retries for Sidekiq [](https://travis-ci.org/railsware/sidekiq_unique_retries)
|
2
|
+
|
3
|
+
This is extension for sidekiq that allows to have unique retries for your unique jobs.
|
4
|
+
It should work for any sidekiq unique job extension if it guarantees that only one unique job can be performing at the same time.
|
5
|
+
Currently this gem supports SidekiqUniqueJobs extension but you may wrote own adapter.
|
6
|
+
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'sidekiq_unique_retries'
|
14
|
+
```
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install sidekiq_unique_retries
|
23
|
+
|
24
|
+
## Authors
|
25
|
+
|
26
|
+
* [Andriy Yanko](http://ayanko.github.io)
|
27
|
+
|
28
|
+
## References
|
29
|
+
|
30
|
+
* https://github.com/mperham/sidekiq
|
31
|
+
* https://github.com/mhenrixon/sidekiq-unique-jobs
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "sidekiq_unique_retries"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'sidekiq_unique_retries/lock'
|
2
|
+
require 'sidekiq_unique_retries/extensions/api'
|
3
|
+
require 'sidekiq_unique_retries/extensions/job_retry'
|
4
|
+
|
5
|
+
module SidekiqUniqueRetries
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_reader :adapter
|
9
|
+
|
10
|
+
def adapter=(name)
|
11
|
+
@adapter = adapter_for(name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def lockable?(item)
|
15
|
+
adapter.lockable?(item)
|
16
|
+
end
|
17
|
+
|
18
|
+
def lock(item)
|
19
|
+
Lock.new(item, adapter).acquire
|
20
|
+
end
|
21
|
+
|
22
|
+
def unlock(item)
|
23
|
+
Lock.new(item, adapter).release
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def adapter_for(object)
|
29
|
+
case object
|
30
|
+
when Symbol
|
31
|
+
load_adapter(object)
|
32
|
+
build_adapter(object)
|
33
|
+
else
|
34
|
+
object
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_adapter(name)
|
39
|
+
require "sidekiq_unique_retries/adapters/#{name}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_adapter(name)
|
43
|
+
class_name = name.to_s.split('_').map(&:capitalize).join
|
44
|
+
klass = self::Adapters.const_get(class_name, false)
|
45
|
+
klass.new
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
self.adapter = :sidekiq_unique_jobs
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module SidekiqUniqueRetries
|
2
|
+
module Adapters
|
3
|
+
class SidekiqUniqueJobs
|
4
|
+
|
5
|
+
JOB_ID_KEY = 'jid'.freeze
|
6
|
+
UNIQUE_DIGEST_KEY = 'unique_digest'.freeze
|
7
|
+
|
8
|
+
def lockable?(item)
|
9
|
+
item.key?(UNIQUE_DIGEST_KEY)
|
10
|
+
end
|
11
|
+
|
12
|
+
def job_id(item)
|
13
|
+
item.fetch(JOB_ID_KEY)
|
14
|
+
end
|
15
|
+
|
16
|
+
def unique_digest(item)
|
17
|
+
item.fetch(UNIQUE_DIGEST_KEY)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'sidekiq/api'
|
2
|
+
|
3
|
+
module SidekiqUniqueRetries
|
4
|
+
module Extensions
|
5
|
+
module SortedEntry
|
6
|
+
|
7
|
+
def delete
|
8
|
+
if SidekiqUniqueRetries.lockable?(item)
|
9
|
+
SidekiqUniqueRetries.unlock(item)
|
10
|
+
end
|
11
|
+
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def retry
|
16
|
+
if SidekiqUniqueRetries.lockable?(item)
|
17
|
+
SidekiqUniqueRetries.unlock(item)
|
18
|
+
end
|
19
|
+
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
def kill
|
24
|
+
if SidekiqUniqueRetries.lockable?(item)
|
25
|
+
SidekiqUniqueRetries.unlock(item)
|
26
|
+
end
|
27
|
+
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Sidekiq::SortedEntry.prepend SidekiqUniqueRetries::Extensions::SortedEntry
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'sidekiq/job_retry'
|
2
|
+
|
3
|
+
module SidekiqUniqueRetries
|
4
|
+
module Extensions
|
5
|
+
module JobRetry
|
6
|
+
|
7
|
+
def attempt_retry(worker, msg, queue, exception)
|
8
|
+
if SidekiqUniqueRetries.lockable?(msg)
|
9
|
+
raise exception unless SidekiqUniqueRetries.lock(msg)
|
10
|
+
end
|
11
|
+
|
12
|
+
super(worker, msg, queue, exception)
|
13
|
+
end
|
14
|
+
|
15
|
+
def retries_exhausted(worker, msg, exception)
|
16
|
+
if SidekiqUniqueRetries.lockable?(msg)
|
17
|
+
SidekiqUniqueRetries.unlock(msg)
|
18
|
+
end
|
19
|
+
|
20
|
+
super(worker, msg, exception)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Sidekiq::JobRetry.prepend SidekiqUniqueRetries::Extensions::JobRetry
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module SidekiqUniqueRetries
|
2
|
+
class Lock
|
3
|
+
|
4
|
+
HASH_KEY = 'uniqueretries'.freeze
|
5
|
+
|
6
|
+
attr_reader \
|
7
|
+
:job_id,
|
8
|
+
:unique_digest
|
9
|
+
|
10
|
+
def initialize(item, adapter)
|
11
|
+
@job_id = adapter.job_id(item)
|
12
|
+
@unique_digest = adapter.unique_digest(item)
|
13
|
+
end
|
14
|
+
|
15
|
+
def acquire
|
16
|
+
lock_id = get_lock
|
17
|
+
|
18
|
+
if lock_id
|
19
|
+
job_id == lock_id
|
20
|
+
else
|
21
|
+
set_lock(job_id)
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def release
|
27
|
+
remove_lock
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def get_lock
|
34
|
+
Sidekiq.redis do |conn|
|
35
|
+
conn.hget HASH_KEY, unique_digest
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def set_lock(value)
|
40
|
+
Sidekiq.redis do |conn|
|
41
|
+
conn.hset HASH_KEY, unique_digest, value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def remove_lock
|
46
|
+
Sidekiq.redis do |conn|
|
47
|
+
conn.hdel HASH_KEY, unique_digest
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "sidekiq_unique_retries"
|
7
|
+
spec.version = "0.1.0"
|
8
|
+
spec.authors = ["Andriy Yanko"]
|
9
|
+
spec.email = ["andriy.yanko@railsware.com"]
|
10
|
+
|
11
|
+
spec.summary = %q{Uniqueness for Sidekiq Retries}
|
12
|
+
spec.homepage = "https://github.com/railsware/sidekiq_unique_retries"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
16
|
+
f.match(%r{^(test|spec|features)/})
|
17
|
+
end
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_dependency "sidekiq", ">= 5.0.0"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.15"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sidekiq_unique_retries
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andriy Yanko
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-09-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: sidekiq
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 5.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 5.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.15'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.15'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- andriy.yanko@railsware.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- ".rspec"
|
78
|
+
- ".travis.yml"
|
79
|
+
- Gemfile
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- bin/console
|
83
|
+
- bin/setup
|
84
|
+
- lib/sidekiq_unique_retries.rb
|
85
|
+
- lib/sidekiq_unique_retries/adapters/sidekiq_unique_jobs.rb
|
86
|
+
- lib/sidekiq_unique_retries/extensions/api.rb
|
87
|
+
- lib/sidekiq_unique_retries/extensions/job_retry.rb
|
88
|
+
- lib/sidekiq_unique_retries/lock.rb
|
89
|
+
- sidekiq_unique_retries.gemspec
|
90
|
+
homepage: https://github.com/railsware/sidekiq_unique_retries
|
91
|
+
licenses:
|
92
|
+
- MIT
|
93
|
+
metadata: {}
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
require_paths:
|
97
|
+
- lib
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
requirements: []
|
109
|
+
rubyforge_project:
|
110
|
+
rubygems_version: 2.6.11
|
111
|
+
signing_key:
|
112
|
+
specification_version: 4
|
113
|
+
summary: Uniqueness for Sidekiq Retries
|
114
|
+
test_files: []
|
115
|
+
has_rdoc:
|