resque-loner 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.rubocop.yml +92 -0
- data/.simplecov +1 -0
- data/.travis.yml +12 -0
- data/CHANGELOG.markdown +11 -0
- data/Gemfile +4 -5
- data/README.markdown +4 -1
- data/Rakefile +13 -41
- data/lib/resque-ext/job.rb +9 -9
- data/lib/resque-ext/resque.rb +4 -9
- data/lib/resque-loner.rb +2 -1
- data/lib/resque-loner/helpers.rb +22 -9
- data/lib/resque-loner/legacy_helpers.rb +91 -0
- data/lib/resque-loner/unique_job.rb +23 -14
- data/lib/resque-loner/version.rb +1 -1
- data/resque-loner.gemspec +41 -32
- data/spec/loner_spec.rb +73 -51
- data/spec/spec_helper.rb +19 -3
- data/spec/support/redis_instance.rb +133 -0
- data/test/airbrake_test.rb +27 -0
- data/test/dump.rdb +0 -0
- data/test/job_hooks_test.rb +191 -52
- data/test/job_plugins_test.rb +33 -31
- data/test/plugin_test.rb +38 -26
- data/{spec/redis-test.conf → test/redis-test-cluster.conf} +4 -4
- data/test/resque-web_test.rb +23 -17
- data/test/resque_failure_redis_test.rb +23 -0
- data/test/resque_test.rb +56 -37
- data/test/test_helper.rb +58 -29
- data/test/worker_test.rb +311 -55
- metadata +157 -58
- data/init.rb +0 -1
- data/rails/init.rb +0 -1
- data/test/hoptoad_test.rb +0 -25
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: de3cf9ac86e6b7d373f9f281805f3a0fe4da5548
|
4
|
+
data.tar.gz: daf48d9aa6bc0a2f9a0afdeac093ab55fc04f1b1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f25db5e2368a0b32d8cc5aaf363ee5b63eaa68dd78ef204b705434df500b376bf7c3cfe50f8819df1d99fdecdf685e42b540fed5e9c8f193a02978a4c587275b
|
7
|
+
data.tar.gz: d6be67b0d07ae6c98d167edca1cf6537d84458137f89c968af4db5f9b8e445974cfd2bf87bb3ea36d5fde29e81143792843cbbc80845e77e0a70b4a2944e6e63
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# This configuration was generated by `rubocop --auto-gen-config`
|
2
|
+
# on 2014-03-20 16:42:32 -0400 using RuboCop version 0.19.1.
|
3
|
+
# The point is for the user to remove these configuration records
|
4
|
+
# one by one as the offenses are removed from the code base.
|
5
|
+
# Note that changes in the inspected code, or installation of new
|
6
|
+
# versions of RuboCop, may require this file to be generated again.
|
7
|
+
|
8
|
+
# Offense count: 1
|
9
|
+
AmbiguousOperator:
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
# Offense count: 1
|
13
|
+
AmbiguousRegexpLiteral:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
# Offense count: 36
|
17
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
18
|
+
ClassAndModuleChildren:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
# Offense count: 5
|
22
|
+
ClassVars:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
# Offense count: 75
|
26
|
+
Documentation:
|
27
|
+
Enabled: false
|
28
|
+
|
29
|
+
# Offense count: 20
|
30
|
+
Encoding:
|
31
|
+
Enabled: false
|
32
|
+
|
33
|
+
# Offense count: 1
|
34
|
+
Eval:
|
35
|
+
Enabled: false
|
36
|
+
|
37
|
+
# Offense count: 1
|
38
|
+
FavorUnlessOverNegatedIf:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
# Offense count: 2
|
42
|
+
# Configuration parameters: Exclude.
|
43
|
+
FileName:
|
44
|
+
Enabled: false
|
45
|
+
|
46
|
+
# Offense count: 27
|
47
|
+
# Configuration parameters: AllowedVariables.
|
48
|
+
GlobalVars:
|
49
|
+
Enabled: false
|
50
|
+
|
51
|
+
# Offense count: 1
|
52
|
+
HandleExceptions:
|
53
|
+
Enabled: false
|
54
|
+
|
55
|
+
# Offense count: 75
|
56
|
+
LineLength:
|
57
|
+
Max: 161
|
58
|
+
|
59
|
+
# Offense count: 1
|
60
|
+
# Configuration parameters: CountComments.
|
61
|
+
MethodLength:
|
62
|
+
Max: 17
|
63
|
+
|
64
|
+
# Offense count: 1
|
65
|
+
ModuleFunction:
|
66
|
+
Enabled: false
|
67
|
+
|
68
|
+
# Offense count: 2
|
69
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
70
|
+
RaiseArgs:
|
71
|
+
Enabled: false
|
72
|
+
|
73
|
+
# Offense count: 3
|
74
|
+
RedundantBegin:
|
75
|
+
Enabled: false
|
76
|
+
|
77
|
+
# Offense count: 1
|
78
|
+
UnlessElse:
|
79
|
+
Enabled: false
|
80
|
+
|
81
|
+
# Offense count: 1
|
82
|
+
UnreachableCode:
|
83
|
+
Enabled: false
|
84
|
+
|
85
|
+
# Offense count: 5
|
86
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
87
|
+
VariableName:
|
88
|
+
Enabled: false
|
89
|
+
|
90
|
+
# Offense count: 11
|
91
|
+
Void:
|
92
|
+
Enabled: false
|
data/.simplecov
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
SimpleCov.start { add_filter '/spec/' } if ENV['COVERAGE']
|
data/.travis.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
---
|
2
|
+
language: ruby
|
3
|
+
rvm:
|
4
|
+
- 1.9.3
|
5
|
+
- 2.1.1
|
6
|
+
env:
|
7
|
+
global:
|
8
|
+
- RESQUE_LONER_DISABLE_TEST_REDIS_SERVER=1
|
9
|
+
- COVERAGE=1
|
10
|
+
- secure: c9PvRm9w0ewSsS1QDogwPCvSXO+xgHm0mcVA+iiUknezitNjDwaTuBqGtLJ/PjMnQ16QfG0ApDvSqqOw9rSjwM7meCqiQZlJRqqyd547PNhbP6J56mtuXvxMM7wvulK/aLeIYwDeON0Do52FSY4l2/oN2QvA2hIvX8RTDyrfdaA=
|
11
|
+
services:
|
12
|
+
- redis-server
|
data/CHANGELOG.markdown
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
1.3.0
|
2
|
+
--------------------------------
|
3
|
+
Enhancements and bug fixes from @mateusdelbianco. Not allowing a job to
|
4
|
+
be executed immediately after execution, another from @mateusdelbianco!
|
5
|
+
Merged @andrejj's fix which removes an unused `#first` from a redis
|
6
|
+
multi call. @kforsman created an internal helpers module to remove the
|
7
|
+
dependency on the deprecated `Resque::Helpers` module. Added RuboCop,
|
8
|
+
SimpleCov, and CodeClimate, plus tweaked some stuff in Travis
|
9
|
+
configuration.
|
10
|
+
|
11
|
+
|
1
12
|
1.2.1
|
2
13
|
--------------------------------
|
3
14
|
Merged @aerodynamik's pull request. Enqueuing and marking as
|
data/Gemfile
CHANGED
@@ -1,8 +1,7 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
1
2
|
source 'http://rubygems.org'
|
3
|
+
|
2
4
|
gemspec
|
3
5
|
|
4
|
-
group :development
|
5
|
-
|
6
|
-
gem 'ruby-debug', :platform => :mri_18
|
7
|
-
gem 'ruby-debug19', :platform => :mri_19
|
8
|
-
end
|
6
|
+
gem 'debugger', group: :development, platform: :mri_19
|
7
|
+
gem 'codeclimate-test-reporter', group: :test, require: nil
|
data/README.markdown
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
Resque-Loner
|
2
2
|
======
|
3
3
|
|
4
|
+
[![Build Status](https://secure.travis-ci.org/resque/resque-loner.png?branch=master)](https://travis-ci.org/resque/resque-loner)
|
5
|
+
[![Code Climate](https://codeclimate.com/github/resque/resque-loner.png)](https://codeclimate.com/github/resque/resque-loner)
|
6
|
+
|
4
7
|
Resque-Loner is a plugin for defunkt/resque which adds unique jobs to resque: Only one job with the same payload per queue.
|
5
8
|
|
6
9
|
|
@@ -20,7 +23,7 @@ Tests
|
|
20
23
|
-----------
|
21
24
|
To make sure this plugin works on your installation, you should run the tests. resque-loner is tested in RSpec, but it also includes resque's original testsuite. You can run all tests specific to resque-loner with `rake spec`.
|
22
25
|
|
23
|
-
To make sure the plugin did not break resque, you can run `rake test` (the standard resque test suite). This runs all tests from the 1.
|
26
|
+
To make sure the plugin did not break resque, you can run `rake test` (the standard resque test suite). This runs all tests from the 1.22.0 version of resque, so make sure you have that version of resque installed, when you run the resque-tests.
|
24
27
|
|
25
28
|
Example
|
26
29
|
--------
|
data/Rakefile
CHANGED
@@ -1,49 +1,32 @@
|
|
1
|
-
#
|
2
|
-
# Setup
|
3
|
-
#
|
4
|
-
|
5
1
|
$LOAD_PATH.unshift 'lib'
|
6
2
|
|
7
|
-
require
|
8
|
-
require
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
9
5
|
Bundler.setup
|
10
6
|
|
11
7
|
require 'rspec/core/rake_task'
|
12
|
-
|
13
8
|
load 'tasks/redis.rake'
|
14
9
|
require 'rake/testtask'
|
15
|
-
|
16
10
|
require 'resque/tasks'
|
17
|
-
|
18
11
|
require 'bundler/gem_tasks'
|
12
|
+
require 'rubocop/rake_task'
|
19
13
|
|
20
14
|
def command?(command)
|
21
15
|
system("type #{command} > /dev/null 2>&1")
|
22
16
|
end
|
23
17
|
|
18
|
+
task default: [:rubocop, :spec]
|
24
19
|
|
25
|
-
|
26
|
-
# Tests
|
27
|
-
#
|
28
|
-
|
29
|
-
task :default => :spec
|
20
|
+
Rubocop::RakeTask.new
|
30
21
|
|
31
|
-
desc
|
22
|
+
desc 'Run specs for resque-loner'
|
32
23
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
33
|
-
t.pattern =
|
24
|
+
t.pattern = 'spec/**/*_spec.rb'
|
34
25
|
t.rspec_opts = %w(-fd -c)
|
35
26
|
end
|
36
27
|
|
37
|
-
# desc "Run resque's test suite to make sure we did not break anything"
|
38
|
-
# task :test do
|
39
|
-
# rg = command?(:rg)
|
40
|
-
# Dir['test/**/*_test.rb'].each do |f|
|
41
|
-
# rg ? sh("rg #{f}") : ruby(f)
|
42
|
-
# end
|
43
|
-
# end
|
44
|
-
|
45
28
|
if command?(:rg)
|
46
|
-
desc
|
29
|
+
desc 'Run the test suite with rg'
|
47
30
|
task :test do
|
48
31
|
Dir['test/**/*_test.rb'].each do |f|
|
49
32
|
sh("rg #{f}")
|
@@ -51,33 +34,22 @@ if command?(:rg)
|
|
51
34
|
end
|
52
35
|
else
|
53
36
|
Rake::TestTask.new do |test|
|
54
|
-
test.libs <<
|
37
|
+
test.libs << 'test'
|
55
38
|
test.test_files = FileList['test/**/*_test.rb']
|
56
39
|
end
|
57
40
|
end
|
58
41
|
|
59
42
|
if command? :kicker
|
60
|
-
desc
|
43
|
+
desc 'Launch Kicker (like autotest)'
|
61
44
|
task :kicker do
|
62
|
-
puts
|
63
|
-
exec
|
45
|
+
puts 'Kicking... (ctrl+c to cancel)'
|
46
|
+
exec 'kicker -e rake test lib examples'
|
64
47
|
end
|
65
48
|
end
|
66
49
|
|
67
|
-
|
68
|
-
#
|
69
|
-
# Install
|
70
|
-
#
|
71
|
-
|
72
|
-
task :install => [ 'redis:install', 'dtach:install' ]
|
73
|
-
|
74
|
-
|
75
|
-
#
|
76
|
-
# Documentation
|
77
|
-
#
|
50
|
+
task :install => ['redis:install', 'dtach:install']
|
78
51
|
|
79
52
|
begin
|
80
53
|
require 'sdoc_helpers'
|
81
54
|
rescue LoadError
|
82
55
|
end
|
83
|
-
|
data/lib/resque-ext/job.rb
CHANGED
@@ -2,24 +2,24 @@
|
|
2
2
|
# Since there were not enough hooks to hook into, I have to overwrite
|
3
3
|
# 3 methods of Resque::Job - the rest of the implementation is in the
|
4
4
|
# proper Plugin namespace.
|
5
|
-
#
|
5
|
+
#
|
6
6
|
module Resque
|
7
7
|
class Job
|
8
|
-
|
9
|
-
|
10
8
|
#
|
11
9
|
# Overwriting original create method to mark an item as queued
|
12
10
|
# after Resque::Job.create has called Resque.push
|
13
11
|
#
|
14
12
|
def self.create_with_loner(queue, klass, *args)
|
15
13
|
return create_without_loner(queue, klass, *args) if Resque.inline?
|
16
|
-
item = { :
|
17
|
-
return
|
14
|
+
item = { class: klass.to_s, args: args }
|
15
|
+
return 'EXISTED' if Resque::Plugins::Loner::Helpers.loner_queued?(queue, item)
|
18
16
|
# multi block returns array of keys
|
17
|
+
create_return_value = false
|
19
18
|
Resque.redis.multi do
|
20
|
-
create_without_loner(queue, klass, *args)
|
19
|
+
create_return_value = create_without_loner(queue, klass, *args)
|
21
20
|
Resque::Plugins::Loner::Helpers.mark_loner_as_queued(queue, item)
|
22
|
-
end
|
21
|
+
end
|
22
|
+
create_return_value
|
23
23
|
end
|
24
24
|
|
25
25
|
#
|
@@ -27,13 +27,13 @@ module Resque
|
|
27
27
|
#
|
28
28
|
def self.reserve_with_loner(queue)
|
29
29
|
item = reserve_without_loner(queue)
|
30
|
-
Resque::Plugins::Loner::Helpers.mark_loner_as_unqueued(
|
30
|
+
Resque::Plugins::Loner::Helpers.mark_loner_as_unqueued(queue, item) if item && !Resque.inline?
|
31
31
|
item
|
32
32
|
end
|
33
33
|
|
34
34
|
#
|
35
35
|
# Overwriting original destroy method to mark all destroyed jobs as unqueued.
|
36
|
-
# Because the original method only returns the amount of jobs destroyed, but not
|
36
|
+
# Because the original method only returns the amount of jobs destroyed, but not
|
37
37
|
# the jobs themselves. Hence Resque::Plugins::Loner::Helpers.job_destroy looks almost
|
38
38
|
# as the original method Resque::Job.destroy. Couldn't make it any dry'er.
|
39
39
|
#
|
data/lib/resque-ext/resque.rb
CHANGED
@@ -1,26 +1,21 @@
|
|
1
1
|
module Resque
|
2
|
-
|
3
|
-
|
4
|
-
enqueued_in?(queue_from_class(klass), klass, *args )
|
2
|
+
def self.enqueued?(klass, *args)
|
3
|
+
enqueued_in?(queue_from_class(klass), klass, *args)
|
5
4
|
end
|
6
5
|
|
7
6
|
def self.enqueued_in?(queue, klass, *args)
|
8
|
-
item = { :
|
7
|
+
item = { class: klass.to_s, args: args }
|
9
8
|
return nil unless Resque::Plugins::Loner::Helpers.item_is_a_unique_job?(item)
|
10
9
|
Resque::Plugins::Loner::Helpers.loner_queued?(queue, item)
|
11
10
|
end
|
12
11
|
|
13
12
|
def self.remove_queue_with_loner_cleanup(queue)
|
14
|
-
|
13
|
+
remove_queue_without_loner_cleanup(queue)
|
15
14
|
Resque::Plugins::Loner::Helpers.cleanup_loners(queue)
|
16
15
|
end
|
17
16
|
|
18
|
-
|
19
17
|
class << self
|
20
|
-
|
21
18
|
alias_method :remove_queue_without_loner_cleanup, :remove_queue
|
22
19
|
alias_method :remove_queue, :remove_queue_with_loner_cleanup
|
23
|
-
|
24
20
|
end
|
25
|
-
|
26
21
|
end
|
data/lib/resque-loner.rb
CHANGED
data/lib/resque-loner/helpers.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
|
+
require 'resque-loner/legacy_helpers'
|
2
|
+
|
1
3
|
module Resque
|
2
4
|
module Plugins
|
3
5
|
module Loner
|
4
6
|
class Helpers
|
5
|
-
extend Resque::
|
7
|
+
extend Resque::Plugins::Loner::LegacyHelpers
|
6
8
|
|
7
9
|
def self.loner_queued?(queue, item)
|
8
10
|
return false unless item_is_a_unique_job?(item)
|
9
|
-
redis.get(unique_job_queue_key(queue, item)) ==
|
11
|
+
redis.get(unique_job_queue_key(queue, item)) == '1'
|
10
12
|
end
|
11
13
|
|
12
14
|
def self.mark_loner_as_queued(queue, item)
|
13
15
|
return unless item_is_a_unique_job?(item)
|
14
16
|
key = unique_job_queue_key(queue, item)
|
15
17
|
redis.set(key, 1)
|
16
|
-
unless(ttl=item_ttl(item)) == -1 # no need to incur overhead for default value
|
18
|
+
unless (ttl = item_ttl(item)) == -1 # no need to incur overhead for default value
|
17
19
|
redis.expire(key, ttl)
|
18
20
|
end
|
19
21
|
end
|
@@ -21,17 +23,21 @@ module Resque
|
|
21
23
|
def self.mark_loner_as_unqueued(queue, job)
|
22
24
|
item = job.is_a?(Resque::Job) ? job.payload : job
|
23
25
|
return unless item_is_a_unique_job?(item)
|
24
|
-
|
26
|
+
unless (ttl = loner_lock_after_execution_period(item)) == 0
|
27
|
+
redis.expire(unique_job_queue_key(queue, item), ttl)
|
28
|
+
else
|
29
|
+
redis.del(unique_job_queue_key(queue, item))
|
30
|
+
end
|
25
31
|
end
|
26
32
|
|
27
33
|
def self.unique_job_queue_key(queue, item)
|
28
|
-
job_key = constantize(item[:class] || item[
|
34
|
+
job_key = constantize(item[:class] || item['class']).redis_key(item)
|
29
35
|
"loners:queue:#{queue}:job:#{job_key}"
|
30
36
|
end
|
31
37
|
|
32
38
|
def self.item_is_a_unique_job?(item)
|
33
39
|
begin
|
34
|
-
klass = constantize(item[:class] || item[
|
40
|
+
klass = constantize(item[:class] || item['class'])
|
35
41
|
klass.included_modules.include?(::Resque::Plugins::UniqueJob)
|
36
42
|
rescue
|
37
43
|
false # Resque testsuite also submits strings as job classes while Resque.enqueue'ing,
|
@@ -40,12 +46,20 @@ module Resque
|
|
40
46
|
|
41
47
|
def self.item_ttl(item)
|
42
48
|
begin
|
43
|
-
constantize(item[:class] || item[
|
49
|
+
constantize(item[:class] || item['class']).loner_ttl
|
44
50
|
rescue
|
45
51
|
-1
|
46
52
|
end
|
47
53
|
end
|
48
54
|
|
55
|
+
def self.loner_lock_after_execution_period(item)
|
56
|
+
begin
|
57
|
+
constantize(item[:class] || item['class']).loner_lock_after_execution_period
|
58
|
+
rescue
|
59
|
+
0
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
49
63
|
def self.job_destroy(queue, klass, *args)
|
50
64
|
klass = klass.to_s
|
51
65
|
redis_queue = "queue:#{queue}"
|
@@ -57,7 +71,7 @@ module Resque
|
|
57
71
|
match &= json['args'] == args unless args.empty?
|
58
72
|
|
59
73
|
if match
|
60
|
-
|
74
|
+
Resque::Plugins::Loner::Helpers.mark_loner_as_unqueued(queue, json)
|
61
75
|
end
|
62
76
|
end
|
63
77
|
end
|
@@ -66,7 +80,6 @@ module Resque
|
|
66
80
|
keys = redis.keys("loners:queue:#{queue}:job:*")
|
67
81
|
redis.del(*keys) unless keys.empty?
|
68
82
|
end
|
69
|
-
|
70
83
|
end
|
71
84
|
end
|
72
85
|
end
|