resque-approval 1.0.1 → 1.2.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.
- data/lib/resque-approval.rb +62 -21
- data/lib/resque-approval/version.rb +1 -1
- data/resque-approval.gemspec +1 -0
- data/spec/lib/resque-approval_spec.rb +131 -35
- data/spec/spec_helper.rb +2 -0
- metadata +23 -12
data/lib/resque-approval.rb
CHANGED
@@ -6,14 +6,14 @@ module Resque
|
|
6
6
|
module Approval
|
7
7
|
def self.pending_job_keys
|
8
8
|
keys = Resque.redis.hkeys('pending_jobs')
|
9
|
-
keys.map! { |key|
|
9
|
+
keys.map! { |key| Resque.decode(key) }
|
10
10
|
keys.sort! { |a, b| a['id'] <=> b['id'] }
|
11
11
|
end
|
12
12
|
|
13
13
|
def before_enqueue_approval(*args)
|
14
14
|
args = args[0] || {}
|
15
15
|
|
16
|
-
requires_approval = args
|
16
|
+
requires_approval = extract_value(args, :requires_approval)
|
17
17
|
if requires_approval
|
18
18
|
enqueue_for_approval(args)
|
19
19
|
allow_enqueue = false
|
@@ -24,52 +24,93 @@ module Resque
|
|
24
24
|
allow_enqueue
|
25
25
|
end
|
26
26
|
|
27
|
+
def before_delayed_enqueue(args)
|
28
|
+
key = extract_value(args, :approval_key)
|
29
|
+
Resque.redis.hdel('pending_jobs', key)
|
30
|
+
end
|
31
|
+
|
27
32
|
def enqueue_for_approval(*args)
|
28
33
|
args = args[0] || {}
|
29
34
|
|
30
|
-
message = args
|
35
|
+
message = extract_value(args, :approval_message)
|
36
|
+
timeout = extract_value(args, :approval_timeout)
|
31
37
|
|
32
|
-
Resque.
|
38
|
+
id = Resque.redis.hlen('pending_jobs')
|
39
|
+
key = build_key(id, message, timeout)
|
33
40
|
|
34
|
-
|
41
|
+
if timeout && Resque.respond_to?(:enqueue_in)
|
42
|
+
approval_args = args.merge(:approval_key => key)
|
43
|
+
Resque.enqueue_in(timeout, self, approval_args)
|
35
44
|
|
36
|
-
|
37
|
-
|
45
|
+
queue = Resque.queue_from_class(self)
|
46
|
+
value = build_value(queue, approval_args)
|
38
47
|
else
|
39
|
-
|
40
|
-
end
|
48
|
+
Resque.enqueue_to(:approval_required, self, args)
|
41
49
|
|
42
|
-
|
43
|
-
|
50
|
+
value = build_value(nil, args)
|
51
|
+
end
|
44
52
|
|
45
53
|
Resque.redis.hset('pending_jobs', key, value)
|
46
54
|
end
|
47
55
|
|
48
56
|
def approve(key)
|
49
|
-
|
50
|
-
|
51
|
-
return false if value.nil?
|
57
|
+
job = remove_from_pending(key)
|
52
58
|
|
53
|
-
|
59
|
+
return false if job.nil?
|
54
60
|
|
55
|
-
Resque.redis.hdel('pending_jobs', key)
|
56
|
-
Resque.redis.lrem('queue:approval_required', 1, job.to_json)
|
57
61
|
Resque.push(Resque.queue_from_class(self), job)
|
58
62
|
|
59
63
|
true
|
60
64
|
end
|
61
65
|
|
62
66
|
def reject(key)
|
67
|
+
!!remove_from_pending(key)
|
68
|
+
end
|
69
|
+
|
70
|
+
def remove_from_pending(key)
|
63
71
|
value = Resque.redis.hget('pending_jobs', key)
|
64
72
|
|
65
|
-
return
|
73
|
+
return if value.nil?
|
66
74
|
|
67
|
-
|
75
|
+
encoded_job = value
|
76
|
+
job = Resque.decode(value)
|
68
77
|
|
69
78
|
Resque.redis.hdel('pending_jobs', key)
|
70
|
-
Resque.redis.lrem('queue:approval_required', 1, job.to_json)
|
71
79
|
|
72
|
-
|
80
|
+
decoded_key = Resque.decode(key)
|
81
|
+
if decoded_key.has_key? 'approval_timeout'
|
82
|
+
Array(Resque.redis.keys("delayed:*")).each do |key|
|
83
|
+
destroyed = Resque.redis.lrem(key, 1, encoded_job)
|
84
|
+
break if destroyed > 0
|
85
|
+
end
|
86
|
+
else
|
87
|
+
Resque.redis.lrem('queue:approval_required', 1, encoded_job)
|
88
|
+
end
|
89
|
+
|
90
|
+
job
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def extract_value(args, key)
|
96
|
+
args.delete(key.to_sym) || args.delete(key.to_s)
|
97
|
+
end
|
98
|
+
|
99
|
+
def build_key(id, message, timeout = nil)
|
100
|
+
key = { :id => id }
|
101
|
+
|
102
|
+
key.merge!(:approval_message => message) if message
|
103
|
+
key.merge!(:approval_timeout => timeout) if timeout
|
104
|
+
|
105
|
+
Resque.encode(key)
|
106
|
+
end
|
107
|
+
|
108
|
+
def build_value(queue = nil, *args)
|
109
|
+
value = { :class => self.to_s, :args => args }
|
110
|
+
|
111
|
+
value.merge!(:queue => queue) if queue
|
112
|
+
|
113
|
+
Resque.encode(value)
|
73
114
|
end
|
74
115
|
end
|
75
116
|
end
|
data/resque-approval.gemspec
CHANGED
@@ -14,6 +14,7 @@ describe "Resque::Plugins::Approval" do
|
|
14
14
|
Resque.remove_queue(:dummy)
|
15
15
|
Resque.remove_queue(:approval_required)
|
16
16
|
Resque.redis.del('pending_jobs')
|
17
|
+
Resque.reset_delayed_queue
|
17
18
|
end
|
18
19
|
|
19
20
|
it "is a valid Resque plugin" do
|
@@ -22,23 +23,22 @@ describe "Resque::Plugins::Approval" do
|
|
22
23
|
|
23
24
|
describe "#pending_job_keys" do
|
24
25
|
it "lists keys (ordered by id) for all jobs that are waiting for approval" do
|
25
|
-
Job.enqueue_for_approval(:approval_message => 'test message 1')
|
26
26
|
Job.enqueue_for_approval
|
27
|
-
Job.enqueue_for_approval(:
|
27
|
+
Job.enqueue_for_approval(:approval_timeout => 10)
|
28
|
+
Job.enqueue_for_approval(:approval_message => 'test message')
|
28
29
|
|
29
|
-
keys = [{'id' => 0
|
30
|
-
{'id' => 1},
|
31
|
-
{'id' => 2, 'approval_message' => 'test message
|
30
|
+
keys = [{ 'id' => 0 },
|
31
|
+
{ 'id' => 1, 'approval_timeout' => 10 },
|
32
|
+
{ 'id' => 2, 'approval_message' => 'test message' }]
|
32
33
|
Resque::Plugins::Approval.pending_job_keys.should == keys
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
36
37
|
describe ".before_enqueue_approval" do
|
37
|
-
context "when a job requires approval
|
38
|
+
context "when a job requires approval" do
|
38
39
|
it "calls enqueue_for_approval" do
|
39
|
-
Job.should_receive(:enqueue_for_approval).
|
40
|
+
Job.should_receive(:enqueue_for_approval).with({})
|
40
41
|
Resque.enqueue(Job, :requires_approval => true)
|
41
|
-
Resque.enqueue(Job, 'requires_approval' => true)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -62,7 +62,7 @@ describe "Resque::Plugins::Approval" do
|
|
62
62
|
end
|
63
63
|
|
64
64
|
it "adds an entry to the 'pending_jobs' hash" do
|
65
|
-
Job.enqueue_for_approval
|
65
|
+
Job.enqueue_for_approval
|
66
66
|
|
67
67
|
key = '{"id":0}'
|
68
68
|
value = '{"class":"Job","args":[{}]}'
|
@@ -70,47 +70,72 @@ describe "Resque::Plugins::Approval" do
|
|
70
70
|
Resque.redis.hget('pending_jobs', key).should == value
|
71
71
|
end
|
72
72
|
|
73
|
-
context "with an approval message
|
73
|
+
context "with an approval message" do
|
74
74
|
it "includes the message in the 'pending_jobs' hash entry" do
|
75
|
-
Job.enqueue_for_approval(:approval_message => '
|
75
|
+
Job.enqueue_for_approval(:approval_message => 'test message')
|
76
76
|
|
77
|
-
key = '{"id":0,"approval_message":"
|
77
|
+
key = '{"id":0,"approval_message":"test message"}'
|
78
78
|
value = '{"class":"Job","args":[{}]}'
|
79
79
|
|
80
80
|
Resque.redis.hget('pending_jobs', key).should == value
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
-
context "with
|
85
|
-
it "includes the
|
86
|
-
Job.enqueue_for_approval(
|
84
|
+
context "with a timeout" do
|
85
|
+
it "includes the timeout in the 'pending_jobs' hash entry" do
|
86
|
+
Job.enqueue_for_approval(:approval_timeout => 10)
|
87
87
|
|
88
|
-
key = '{"id":0,"
|
89
|
-
|
88
|
+
key = '{"id":0,"approval_timeout":10}'
|
89
|
+
args = { :approval_key => key }
|
90
|
+
value = { :class => Job, :args => [args], :queue => :dummy }
|
91
|
+
value = Resque.encode(value)
|
90
92
|
|
91
93
|
Resque.redis.hget('pending_jobs', key).should == value
|
92
94
|
end
|
95
|
+
|
96
|
+
it "schedules the job" do
|
97
|
+
Resque.count_all_scheduled_jobs.should == 0
|
98
|
+
|
99
|
+
Job.enqueue_for_approval(:approval_timeout => 10)
|
100
|
+
|
101
|
+
Resque.count_all_scheduled_jobs.should == 1
|
102
|
+
end
|
103
|
+
|
104
|
+
it "does not add the job to the appoval queue" do
|
105
|
+
Job.enqueue_for_approval(:approval_timeout => 10)
|
106
|
+
Resque.size(:approval_required).should == 0
|
107
|
+
end
|
93
108
|
end
|
94
109
|
end
|
95
110
|
|
96
111
|
describe ".approve" do
|
97
|
-
it "
|
112
|
+
it "calls .remove_from_pending" do
|
98
113
|
key = '{"id":0}'
|
99
114
|
|
100
|
-
|
115
|
+
Job.should_receive(:remove_from_pending).with(key)
|
101
116
|
Job.approve(key)
|
117
|
+
end
|
118
|
+
|
119
|
+
context "without a timeout" do
|
120
|
+
it "adds the job to its normal queue" do
|
121
|
+
key = '{"id":0}'
|
122
|
+
|
123
|
+
Job.enqueue_for_approval
|
124
|
+
Job.approve(key)
|
102
125
|
|
103
|
-
|
104
|
-
|
126
|
+
Resque.size(:dummy).should == 1
|
127
|
+
end
|
105
128
|
end
|
106
129
|
|
107
|
-
|
108
|
-
|
130
|
+
context "with a timeout" do
|
131
|
+
it "adds the job to its normal queue" do
|
132
|
+
key = '{"id":0,"approval_timeout":10}'
|
109
133
|
|
110
|
-
|
111
|
-
|
134
|
+
Job.enqueue_for_approval(:approval_timeout => 10)
|
135
|
+
Job.approve(key)
|
112
136
|
|
113
|
-
|
137
|
+
Resque.size(:dummy).should == 1
|
138
|
+
end
|
114
139
|
end
|
115
140
|
|
116
141
|
it "returns false when key can not be found" do
|
@@ -119,35 +144,106 @@ describe "Resque::Plugins::Approval" do
|
|
119
144
|
end
|
120
145
|
|
121
146
|
describe ".reject" do
|
122
|
-
it "
|
147
|
+
it "calls .remove_from_pending" do
|
123
148
|
key = '{"id":0}'
|
124
149
|
|
125
|
-
|
150
|
+
Job.should_receive(:remove_from_pending).with(key)
|
126
151
|
Job.reject(key)
|
127
|
-
|
128
|
-
Resque.size(:approval_required).should == 0
|
129
152
|
end
|
130
153
|
|
131
154
|
it "does not add the job to its normal queue" do
|
132
155
|
key = '{"id":0}'
|
133
156
|
|
134
|
-
|
157
|
+
Job.enqueue_for_approval
|
135
158
|
Job.reject(key)
|
136
159
|
|
137
160
|
Resque.size(:dummy).should == 0
|
138
161
|
end
|
139
162
|
|
163
|
+
it "returns false when key can not be found" do
|
164
|
+
Job.reject('bad key').should == false
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe ".remove_from_pending" do
|
169
|
+
context "without a timeout" do
|
170
|
+
it "deletes the job from the approval queue" do
|
171
|
+
key = '{"id":0}'
|
172
|
+
|
173
|
+
Job.enqueue_for_approval
|
174
|
+
Job.remove_from_pending(key)
|
175
|
+
|
176
|
+
Resque.size(:approval_required).should == 0
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context "with a timeout" do
|
181
|
+
it "unschedules the job" do
|
182
|
+
key = '{"id":0,"approval_timeout":10}'
|
183
|
+
|
184
|
+
Job.enqueue_for_approval(:approval_timeout => 10)
|
185
|
+
|
186
|
+
Resque.count_all_scheduled_jobs.should == 1
|
187
|
+
|
188
|
+
Job.remove_from_pending(key)
|
189
|
+
|
190
|
+
Resque.count_all_scheduled_jobs.should == 0
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
140
194
|
it "deletes the entry in the 'pending_jobs' hash" do
|
141
195
|
key = '{"id":0}'
|
142
196
|
|
143
|
-
|
144
|
-
Job.
|
197
|
+
Job.enqueue_for_approval
|
198
|
+
Job.remove_from_pending(key)
|
145
199
|
|
146
200
|
Resque.redis.hget('pending_jobs', key).should be_nil
|
147
201
|
end
|
148
202
|
|
149
|
-
it "returns
|
150
|
-
|
203
|
+
it "returns job when key can be found" do
|
204
|
+
key = '{"id":0}'
|
205
|
+
job = { 'class' => 'Job', 'args' => [{}] }
|
206
|
+
|
207
|
+
Job.enqueue_for_approval
|
208
|
+
job = Job.remove_from_pending(key).should == job
|
209
|
+
end
|
210
|
+
|
211
|
+
it "returns nil when key can not be found" do
|
212
|
+
Job.remove_from_pending('bad key').should == nil
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe ".extract_value" do
|
217
|
+
context "when key is a symbol" do
|
218
|
+
it "deletes and returns value by symbol-referenced key" do
|
219
|
+
hash = { :key => 1 }
|
220
|
+
|
221
|
+
Job.send(:extract_value, hash, :key).should == 1
|
222
|
+
hash.should == {}
|
223
|
+
end
|
224
|
+
|
225
|
+
it "deletes and returns value by string-referenced key" do
|
226
|
+
hash = { :key => 1 }
|
227
|
+
|
228
|
+
Job.send(:extract_value, hash, 'key').should == 1
|
229
|
+
hash.should == {}
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
context "when key is a string" do
|
234
|
+
it "deletes and returns value by symbol-referenced key" do
|
235
|
+
hash = { 'key' => 1 }
|
236
|
+
|
237
|
+
Job.send(:extract_value, hash, :key).should == 1
|
238
|
+
hash.should == {}
|
239
|
+
end
|
240
|
+
|
241
|
+
it "deletes and returns value by string-referenced key" do
|
242
|
+
hash = { 'key' => 1 }
|
243
|
+
|
244
|
+
Job.send(:extract_value, hash, 'key').should == 1
|
245
|
+
hash.should == {}
|
246
|
+
end
|
151
247
|
end
|
152
248
|
end
|
153
249
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-approval
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06-
|
12
|
+
date: 2012-06-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: resque
|
16
|
-
requirement: &
|
16
|
+
requirement: &11915740 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *11915740
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rake
|
27
|
-
requirement: &
|
27
|
+
requirement: &11910380 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *11910380
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec
|
38
|
-
requirement: &
|
38
|
+
requirement: &11908520 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *11908520
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: guard
|
49
|
-
requirement: &
|
49
|
+
requirement: &11907760 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *11907760
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: guard-rspec
|
60
|
-
requirement: &
|
60
|
+
requirement: &11907160 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,7 +65,18 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *11907160
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: resque-scheduler
|
71
|
+
requirement: &11906580 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *11906580
|
69
80
|
description: ! "A Resque plugin allowing jobs to be sent to a temporary\n queue
|
70
81
|
to await approval. Once the job is approved, it\n is placed
|
71
82
|
on its normal queue."
|