resque-loner 0.1.3 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|