Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the possibility to clear the hash #215

Merged
merged 7 commits into from
Apr 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 2 additions & 31 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
@@ -1,36 +1,7 @@
---
engines:
csslint:
enabled: true
duplication:
enabled: true
config:
languages:
- ruby
- javascript
- python
- php
eslint:
enabled: true
fixme:
enabled: true
rubocop:
enabled: true
ratings:
paths:
- "**.css"
- "**.inc"
- "**.js"
- "**.jsx"
- "**.module"
- "**.php"
- "**.py"
- "**.rb"
exclude_paths:
- spec/
engines:
bundler-audit:
enabled: true
enabled: false
fixme:
enabled: true
duplication:
Expand All @@ -47,7 +18,7 @@ ratings:
- "**.rb"
exclude_paths:
- Gemfile
- *.gemspec
- "*.gemspec"
- Appraisals
- spec/**/*.rb
- gemfiles/**/*
Expand Down
4 changes: 2 additions & 2 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ insert_final_newline = true
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = true
[*.{md,slim,haml}]
trim_trailing_whitespace = false
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Metrics/CyclomaticComplexity:
Max: 7

Metrics/LineLength:
Max: 108
Max: 120

Metrics/MethodLength:
Max: 13
Expand Down
8 changes: 4 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
sudo: false
language: ruby
cache: bundler
before_install:
- rvm get head
- gem update --system
- gem install bundler
# before_install:
# - rvm get head
# - gem update --system
# - gem install bundler
services:
- redis-server
script:
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## v5.0.1

- Added a command line util for cleaning out expired keys
- Use `SidekiqUniqueJobs.logger` instead of spreading out `Sidekiq.logger` everywhere.

## v5.0.0

- Only support Sidekiq >= 4
Expand Down
6 changes: 5 additions & 1 deletion lib/sidekiq-unique-jobs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,14 @@ def config
default_queue_lock_expiration: 30 * 60,
default_run_lock_expiration: 60,
default_lock: :while_executing,
redis_test_mode: :redis # :mock
redis_test_mode: :redis, # :mock
)
end

def logger
Sidekiq.logger
end

def default_lock
config.default_lock
end
Expand Down
7 changes: 3 additions & 4 deletions lib/sidekiq/simulator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

module Sidekiq
class Simulator
extend Forwardable
def_delegator SidekiqUniqueJobs, :logger

attr_reader :queues, :launcher

def self.process_queue(queue)
Expand Down Expand Up @@ -67,9 +70,5 @@ def sidekiq_options(queues = [])
verbose: false,
logfile: './tmp/sidekiq.log' }
end

def logger
@logger ||= Sidekiq.logger
end
end
end
32 changes: 27 additions & 5 deletions lib/sidekiq_unique_jobs/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,52 @@

module SidekiqUniqueJobs
class Cli < Thor
# def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel)
# @argv, @stdin, @stdout, @stderr, @kernel = argv, stdin, stdout, stderr, kernel
# end

def self.banner(command, _namespace = nil, _subcommand = false)
"jobs #{@package_name} #{command.usage}"
end

desc 'keys PATTERN', 'list all unique keys and their expiry time'
option :count, aliases: :c, type: :numeric, default: 1000, desc: 'The max number of keys to return'
def keys(pattern)
Util.keys(pattern, options[:count])
keys = Util.keys(pattern, options[:count])
say "Found #{keys.size} keys matching '#{pattern}':"
print_in_columns(keys.sort) if keys.any?
end

desc 'del PATTERN', 'deletes unique keys from redis by pattern'
option :dry_run, aliases: :d, type: :boolean, desc: 'set to false to perform deletion'
option :count, aliases: :c, type: :numeric, default: 1000, desc: 'The max number of keys to return'
def del(pattern)
Util.del(pattern, options[:count], options[:dry_run])
deleted_count = Util.del(pattern, options[:count], options[:dry_run])
say "Deleted #{deleted_count} keys matching '#{pattern}'"
end

desc 'expire', 'removes all expired unique keys from the hash in redis'
def expire
expired = Util.expire
say "Removed #{expired.values.size} left overs from redis."
print_in_columns(expired.values)
end

desc 'console', 'drop into a console with easy access to helper methods'
def console
puts "Use `keys '*', 1000 to display the first 1000 unique keys matching '*'"
puts "Use `del '*', 1000, true (default) to see how many keys would be deleted for the pattern '*'"
puts "Use `del '*', 1000, false to delete the first 1000 keys matching '*'"
say "Use `keys '*', 1000 to display the first 1000 unique keys matching '*'"
say "Use `del '*', 1000, true (default) to see how many keys would be deleted for the pattern '*'"
say "Use `del '*', 1000, false to delete the first 1000 keys matching '*'"
Object.include SidekiqUniqueJobs::Util
console_class.start
end

private

def logger
SidekiqUniqueJobs.logger
end

def console_class
require 'pry'
Pry
Expand Down
20 changes: 6 additions & 14 deletions lib/sidekiq_unique_jobs/lock/until_executed.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,17 @@ def unlock(scope)
unlock_by_key(unique_key, item[JID_KEY], redis_pool)
end

# rubocop:disable MethodLength
def lock(scope)
if scope.to_sym != :client
raise ArgumentError, "#{scope} middleware can't #{__method__} #{unique_key}"
end

result = Scripts.call(:acquire_lock, redis_pool,
keys: [unique_key],
argv: [item[JID_KEY], max_lock_time])
case result
when 1
logger.debug { "successfully locked #{unique_key} for #{max_lock_time} seconds" }
true
when 0
logger.debug { "failed to acquire lock for #{unique_key}" }
false
else
raise "#{__method__} returned an unexpected value (#{result})"
end
Scripts::AcquireLock.execute(
redis_pool,
unique_key,
item[JID_KEY],
max_lock_time
)
end
# rubocop:enable MethodLength

Expand Down
14 changes: 8 additions & 6 deletions lib/sidekiq_unique_jobs/scripts.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
require 'pathname'
require 'digest/sha1'
require 'concurrent/map'
require 'sidekiq_unique_jobs/scripts/acquire_lock'
require 'sidekiq_unique_jobs/scripts/release_lock'

module SidekiqUniqueJobs
ScriptError = Class.new(StandardError)
ScriptError = Class.new(StandardError)
UniqueKeyMissing = Class.new(ArgumentError)
JidMissing = Class.new(ArgumentError)
MaxLockTimeMissing = Class.new(ArgumentError)
UnexpectedValue = Class.new(StandardError)

module Scripts
LUA_PATHNAME ||= Pathname.new(__FILE__).dirname.join('../../redis').freeze
Expand All @@ -14,11 +20,7 @@ module Scripts
module_function

extend SingleForwardable
def_delegator :SidekiqUniqueJobs, :connection

def logger
Sidekiq.logger
end
def_delegators :SidekiqUniqueJobs, :connection, :logger

def call(file_name, redis_pool, options = {}) # rubocop:disable MethodLength
connection(redis_pool) do |redis|
Expand Down
45 changes: 45 additions & 0 deletions lib/sidekiq_unique_jobs/scripts/acquire_lock.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
module SidekiqUniqueJobs
module Scripts
class AcquireLock
extend Forwardable
def_delegator SidekiqUniqueJobs, :logger

def self.execute(redis_pool, unique_key, jid, max_lock_time)
new(redis_pool, unique_key, jid, max_lock_time).execute
end

attr_reader :redis_pool, :unique_key, :jid, :max_lock_time

def initialize(_redis_pool, unique_key, jid, max_lock_time)
raise UniqueKeyMissing, 'unique_key is required' if unique_key.nil?
raise JidMissing, 'jid is required' if jid.nil?
raise MaxLockTimeMissing, 'max_lock_time is required' if max_lock_time.nil?

@unique_key = unique_key
@jid = jid
@max_lock_time = max_lock_time
end

def execute
result = Scripts.call(:acquire_lock, redis_pool,
keys: [unique_key],
argv: [jid, max_lock_time])

handle_result(result)
end

def handle_result(result)
case result
when 1
logger.debug { "successfully acquired lock #{unique_key} for #{max_lock_time} seconds" }
true
when 0
logger.debug { "failed to acquire lock for #{unique_key}" }
false
else
raise UnexpectedValue, "failed to acquire lock : unexpected return value (#{result})"
end
end
end
end
end
47 changes: 47 additions & 0 deletions lib/sidekiq_unique_jobs/scripts/release_lock.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
module SidekiqUniqueJobs
module Scripts
class ReleaseLock
extend Forwardable
def_delegator SidekiqUniqueJobs, :logger

def self.execute(redis_pool, unique_key, jid)
new(redis_pool, unique_key, jid).execute
end

attr_reader :redis_pool, :unique_key, :jid

def initialize(redis_pool, unique_key, jid)
raise UniqueKeyMissing, 'unique_key is required' if unique_key.nil?
raise JidMissing, 'jid is required' if jid.nil?

@redis_pool = redis_pool
@unique_key = unique_key
@jid = jid
end

def execute
result = Scripts.call(:release_lock, redis_pool,
keys: [unique_key],
argv: [jid])

handle_result(result)
end

def handle_result(result)
case result
when 1
logger.debug { "successfully unlocked #{unique_key}" }
true
when 0
logger.debug { "expiring lock #{unique_key} is not owned by #{jid}" }
false
when -1
logger.debug { "#{unique_key} is not a known key" }
false
else
raise UnexpectedValue, "failed to release lock : unexpected return value (#{result})"
end
end
end
end
end
2 changes: 1 addition & 1 deletion lib/sidekiq_unique_jobs/testing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class << self

module Testing
def call_ext(file_name, redis_pool, options = {})
if SidekiqUniqueJobs.config.redis_test_mode == :mock
if SidekiqUniqueJobs.mocked?
SidekiqUniqueJobs::ScriptMock.call(file_name, redis_pool, options)
else
call_orig(file_name, redis_pool, options)
Expand Down
6 changes: 3 additions & 3 deletions lib/sidekiq_unique_jobs/unique_args.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ def self.digest(item)
def initialize(job)
Sidekiq::Logging.with_context(CLASS_NAME) do
@item = job
@worker_class ||= worker_class_constantize(@item[CLASS_KEY])
@worker_class ||= worker_class_constantize(@item[CLASS_KEY])
@item[UNIQUE_PREFIX_KEY] ||= unique_prefix
@item[UNIQUE_ARGS_KEY] = unique_args(@item[ARGS_KEY]) # SIC! Calculate unique_args unconditionally
@item[UNIQUE_DIGEST_KEY] = unique_digest
@item[UNIQUE_ARGS_KEY] = unique_args(@item[ARGS_KEY])
@item[UNIQUE_DIGEST_KEY] = unique_digest
end
end

Expand Down
22 changes: 4 additions & 18 deletions lib/sidekiq_unique_jobs/unlockable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,20 @@ def unlock(item)
end

def unlock_by_key(unique_key, jid, redis_pool = nil)
result = Scripts.call(:release_lock, redis_pool, keys: [unique_key], argv: [jid])
after_unlock(result, __method__, unique_key, jid)
return false unless Scripts::ReleaseLock.execute(redis_pool, unique_key, jid)
after_unlock(jid)
end

def after_unlock(result, calling_method, unique_key, jid) # rubocop:disable Metrics/MethodLength
def after_unlock(jid)
ensure_job_id_removed(jid)

case result
when 1
logger.debug { "successfully unlocked #{unique_key}" }
true
when 0
logger.debug { "expiring lock #{unique_key} is not owned by #{jid}" }
false
when -1
logger.debug { "#{unique_key} is not a known key" }
false
else
raise "#{calling_method} returned an unexpected value (#{result})"
end
end

def ensure_job_id_removed(jid)
Sidekiq.redis { |redis| redis.hdel(SidekiqUniqueJobs::HASH_KEY, jid) }
end

def logger
Sidekiq.logger
SidekiqUniqueJobs.logger
end
end
end
Loading