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.
@@ -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
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,9 @@
1
+ sudo: false
2
+ language: ruby
3
+ services:
4
+ - redis-server
5
+ rvm:
6
+ - 2.4.1
7
+ cache: bundler
8
+ script:
9
+ - bundle exec rspec
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'redis-namespace'
@@ -0,0 +1,31 @@
1
+ # Unique Retries for Sidekiq [![Build Status](https://travis-ci.org/railsware/sidekiq_unique_retries.svg?branch=master)](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
@@ -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,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__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -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: