resque-loner 0.1.3 → 1.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.
- data/README.markdown +8 -3
- data/lib/resque-ext/job.rb +6 -6
- data/lib/resque-ext/resque.rb +11 -11
- data/lib/resque-loner/helpers.rb +9 -8
- data/lib/resque-loner/unique_job.rb +39 -7
- data/lib/resque-loner/version.rb +1 -1
- metadata +45 -27
data/README.markdown
CHANGED
@@ -10,13 +10,18 @@ Installation
|
|
10
10
|
|
11
11
|
First install the gem:
|
12
12
|
|
13
|
-
$ gem install resque-loner
|
13
|
+
$ gem install resque-loner
|
14
14
|
|
15
15
|
Then include it in your app:
|
16
16
|
|
17
17
|
require 'resque-loner'
|
18
18
|
|
19
|
-
|
19
|
+
|
20
|
+
Tests
|
21
|
+
-----------
|
22
|
+
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`.
|
23
|
+
|
24
|
+
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.10.0 version of resque, so make sure you have that version of resque installed, when you run the resque-tests.
|
20
25
|
|
21
26
|
Example
|
22
27
|
--------
|
@@ -90,7 +95,7 @@ The last part of this key is the job's ID, which is pretty much your queue item'
|
|
90
95
|
|
91
96
|
{ 'class': 'CacheSweeper', 'args': [1] }`
|
92
97
|
|
93
|
-
The default method to create a job ID from these parameters is to do some normalization on the payload and then md5'ing it (defined in `Resque::Plugins::
|
98
|
+
The default method to create a job ID from these parameters is to do some normalization on the payload and then md5'ing it (defined in `Resque::Plugins::UniqueJob#redis_key`).
|
94
99
|
|
95
100
|
You could also use the whole payload or anything else as a redis key, as long as you make sure these requirements are met:
|
96
101
|
|
data/lib/resque-ext/job.rb
CHANGED
@@ -5,8 +5,8 @@
|
|
5
5
|
#
|
6
6
|
module Resque
|
7
7
|
class Job
|
8
|
-
|
9
|
-
|
8
|
+
|
9
|
+
|
10
10
|
#
|
11
11
|
# Overwriting original create method to mark an item as queued
|
12
12
|
# after Resque::Job.create has called Resque.push
|
@@ -18,7 +18,7 @@ module Resque
|
|
18
18
|
Resque::Plugins::Loner::Helpers.mark_loner_as_queued(queue, item)
|
19
19
|
job
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
#
|
23
23
|
# Overwriting original reserve method to mark an item as unqueued
|
24
24
|
#
|
@@ -27,7 +27,7 @@ module Resque
|
|
27
27
|
Resque::Plugins::Loner::Helpers.mark_loner_as_unqueued( queue, item ) if item
|
28
28
|
item
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
#
|
32
32
|
# Overwriting original destroy method to mark all destroyed jobs as unqueued.
|
33
33
|
# Because the original method only returns the amount of jobs destroyed, but not
|
@@ -38,7 +38,7 @@ module Resque
|
|
38
38
|
Resque::Plugins::Loner::Helpers.job_destroy(queue, klass, *args)
|
39
39
|
destroy_without_loner(queue, klass, *args)
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
#
|
43
43
|
# Chain..
|
44
44
|
#
|
@@ -51,4 +51,4 @@ module Resque
|
|
51
51
|
alias_method :destroy, :destroy_with_loner
|
52
52
|
end
|
53
53
|
end
|
54
|
-
end
|
54
|
+
end
|
data/lib/resque-ext/resque.rb
CHANGED
@@ -1,37 +1,37 @@
|
|
1
1
|
module Resque
|
2
|
-
|
2
|
+
|
3
3
|
#
|
4
4
|
# Why force one job type into one queue?
|
5
5
|
#
|
6
6
|
def self.enqueue_to( queue, klass, *args )
|
7
7
|
Job.create(queue, klass, *args)
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def self.dequeue_from( queue, klass, *args)
|
11
11
|
Job.destroy(queue, klass, *args)
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def self.enqueued?( klass, *args)
|
15
15
|
enqueued_in?(queue_from_class(klass), klass, *args )
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def self.enqueued_in?(queue, klass, *args)
|
19
19
|
item = { :class => klass.to_s, :args => args }
|
20
20
|
return nil unless Resque::Plugins::Loner::Helpers.item_is_a_unique_job?(item)
|
21
21
|
Resque::Plugins::Loner::Helpers.loner_queued?(queue, item)
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def self.remove_queue_with_loner_cleanup(queue)
|
25
25
|
self.remove_queue_without_loner_cleanup(queue)
|
26
26
|
Resque::Plugins::Loner::Helpers.cleanup_loners(queue)
|
27
27
|
end
|
28
|
-
|
29
|
-
|
28
|
+
|
29
|
+
|
30
30
|
class << self
|
31
|
-
|
31
|
+
|
32
32
|
alias_method :remove_queue_without_loner_cleanup, :remove_queue
|
33
33
|
alias_method :remove_queue, :remove_queue_with_loner_cleanup
|
34
|
-
|
34
|
+
|
35
35
|
end
|
36
|
-
|
37
|
-
end
|
36
|
+
|
37
|
+
end
|
data/lib/resque-loner/helpers.rb
CHANGED
@@ -8,7 +8,7 @@ module Resque
|
|
8
8
|
return false unless item_is_a_unique_job?(item)
|
9
9
|
redis.get(unique_job_queue_key(queue, item)) == "1"
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def self.mark_loner_as_queued(queue, item)
|
13
13
|
return unless item_is_a_unique_job?(item)
|
14
14
|
redis.set(unique_job_queue_key(queue, item), 1)
|
@@ -24,16 +24,16 @@ module Resque
|
|
24
24
|
job_key = constantize(item[:class] || item["class"]).redis_key(item)
|
25
25
|
"loners:queue:#{queue}:job:#{job_key}"
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def self.item_is_a_unique_job?(item)
|
29
29
|
begin
|
30
30
|
klass = constantize(item[:class] || item["class"])
|
31
|
-
klass.
|
31
|
+
klass.included_modules.include?(::Resque::Plugins::UniqueJob)
|
32
32
|
rescue
|
33
33
|
false # Resque testsuite also submits strings as job classes while Resque.enqueue'ing,
|
34
34
|
end # so resque-loner should not start throwing up when that happens.
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def self.job_destroy(queue, klass, *args)
|
38
38
|
klass = klass.to_s
|
39
39
|
redis_queue = "queue:#{queue}"
|
@@ -49,12 +49,13 @@ module Resque
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
def self.cleanup_loners(queue)
|
54
|
-
redis.
|
54
|
+
keys = redis.keys("loners:queue:#{queue}:job:*")
|
55
|
+
redis.del(*keys) unless keys.empty?
|
55
56
|
end
|
56
|
-
|
57
|
+
|
57
58
|
end
|
58
59
|
end
|
59
60
|
end
|
60
|
-
end
|
61
|
+
end
|
@@ -1,27 +1,59 @@
|
|
1
1
|
require 'digest/md5'
|
2
2
|
|
3
3
|
#
|
4
|
-
# If you want your job to be unique,
|
4
|
+
# If you want your job to be unique, include this module in it. If you wish,
|
5
5
|
# you can overwrite this implementation of redis_key to fit your needs
|
6
6
|
#
|
7
7
|
module Resque
|
8
8
|
module Plugins
|
9
|
-
module
|
10
|
-
|
11
|
-
|
9
|
+
module UniqueJob
|
10
|
+
|
11
|
+
def self.included(base)
|
12
|
+
base.extend ClassMethods
|
13
|
+
base.class_eval do
|
14
|
+
base.send(:extend, Resque::Helpers)
|
15
|
+
end
|
16
|
+
end # self.included
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
|
12
20
|
|
13
21
|
#
|
14
22
|
# Payload is what Resque stored for this job along with the job's class name.
|
15
23
|
# On a Resque with no plugins installed, this is a hash containing :class and :args
|
16
24
|
#
|
17
|
-
def
|
25
|
+
def redis_key(payload)
|
18
26
|
payload = decode(encode(payload)) # This is the cycle the data goes when being enqueued/dequeued
|
19
27
|
job = payload[:class] || payload["class"]
|
20
|
-
args = payload[:args] || payload["args"]
|
28
|
+
args = (payload[:args] || payload["args"])
|
29
|
+
args.map! do |arg|
|
30
|
+
arg.is_a?(Hash) ? arg.sort : arg
|
31
|
+
end
|
32
|
+
|
21
33
|
digest = Digest::MD5.hexdigest encode(:class => job, :args => args)
|
22
34
|
digest
|
23
35
|
end
|
36
|
+
end # ClassMethods
|
37
|
+
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Resque
|
44
|
+
module Plugins
|
45
|
+
module Loner
|
46
|
+
class UniqueJob
|
47
|
+
|
48
|
+
include Resque::Plugins::UniqueJob
|
49
|
+
|
50
|
+
def self.inherited(host)
|
51
|
+
super(host)
|
52
|
+
return if @__unique_job_warned
|
53
|
+
warn "Inherit Resque::Plugins::Loner::UniqueJob is deprecated. Include Resque::Plugins::UniqueJob module instead."
|
54
|
+
@__unique_job_warned = true
|
55
|
+
end
|
24
56
|
end
|
25
57
|
end
|
26
58
|
end
|
27
|
-
end
|
59
|
+
end
|
data/lib/resque-loner/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-loner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
- 3
|
10
|
-
version: 0.1.3
|
4
|
+
prerelease:
|
5
|
+
version: 1.0.1
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Jannis Hermanns
|
@@ -15,7 +10,7 @@ autorequire:
|
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
12
|
|
18
|
-
date:
|
13
|
+
date: 2011-07-15 00:00:00 +02:00
|
19
14
|
default_executable:
|
20
15
|
dependencies:
|
21
16
|
- !ruby/object:Gem::Dependency
|
@@ -26,34 +21,63 @@ dependencies:
|
|
26
21
|
requirements:
|
27
22
|
- - ~>
|
28
23
|
- !ruby/object:Gem::Version
|
29
|
-
hash: 15
|
30
|
-
segments:
|
31
|
-
- 1
|
32
|
-
- 0
|
33
24
|
version: "1.0"
|
34
25
|
type: :runtime
|
35
26
|
version_requirements: *id001
|
36
27
|
- !ruby/object:Gem::Dependency
|
37
|
-
name:
|
28
|
+
name: bundler
|
38
29
|
prerelease: false
|
39
30
|
requirement: &id002 !ruby/object:Gem::Requirement
|
40
31
|
none: false
|
41
32
|
requirements:
|
42
|
-
- -
|
33
|
+
- - ~>
|
43
34
|
- !ruby/object:Gem::Version
|
44
|
-
|
45
|
-
segments:
|
46
|
-
- 0
|
47
|
-
version: "0"
|
35
|
+
version: 1.0.0
|
48
36
|
type: :development
|
49
37
|
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: rake
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.8.7
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: rack-test
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ~>
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 0.5.7
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: rspec
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.5.0
|
69
|
+
type: :development
|
70
|
+
version_requirements: *id005
|
50
71
|
description: |
|
51
72
|
Makes sure that for special jobs, there can be only one job with the same workload in one queue.
|
52
73
|
|
53
74
|
Example:
|
54
|
-
class CacheSweeper
|
75
|
+
class CacheSweeper
|
76
|
+
|
77
|
+
include Resque::Plugins::UniqueJob
|
78
|
+
|
55
79
|
@queue = :cache_sweeps
|
56
|
-
|
80
|
+
|
57
81
|
def self.perform(article_id)
|
58
82
|
# Cache Me If You Can...
|
59
83
|
end
|
@@ -89,23 +113,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
113
|
requirements:
|
90
114
|
- - ">="
|
91
115
|
- !ruby/object:Gem::Version
|
92
|
-
hash: 3
|
93
|
-
segments:
|
94
|
-
- 0
|
95
116
|
version: "0"
|
96
117
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
118
|
none: false
|
98
119
|
requirements:
|
99
120
|
- - ">="
|
100
121
|
- !ruby/object:Gem::Version
|
101
|
-
hash: 3
|
102
|
-
segments:
|
103
|
-
- 0
|
104
122
|
version: "0"
|
105
123
|
requirements: []
|
106
124
|
|
107
125
|
rubyforge_project: resque-loner
|
108
|
-
rubygems_version: 1.
|
126
|
+
rubygems_version: 1.5.2
|
109
127
|
signing_key:
|
110
128
|
specification_version: 3
|
111
129
|
summary: Adds unique jobs to resque
|