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.
@@ -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| JSON.parse(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.delete(:requires_approval) || args.delete('requires_approval')
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.delete(:approval_message) || args.delete('approval_message')
35
+ message = extract_value(args, :approval_message)
36
+ timeout = extract_value(args, :approval_timeout)
31
37
 
32
- Resque.enqueue_to(:approval_required, self, args)
38
+ id = Resque.redis.hlen('pending_jobs')
39
+ key = build_key(id, message, timeout)
33
40
 
34
- id = Resque.size(:approval_required) - 1
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
- if message
37
- key = {:id => id, :approval_message => message}.to_json
45
+ queue = Resque.queue_from_class(self)
46
+ value = build_value(queue, approval_args)
38
47
  else
39
- key = { :id => id }.to_json
40
- end
48
+ Resque.enqueue_to(:approval_required, self, args)
41
49
 
42
- job = Resque.peek(:approval_required, id)
43
- value = job.to_json
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
- value = Resque.redis.hget('pending_jobs', key)
50
-
51
- return false if value.nil?
57
+ job = remove_from_pending(key)
52
58
 
53
- job = JSON.parse(value)
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 false if value.nil?
73
+ return if value.nil?
66
74
 
67
- job = JSON.parse(value)
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
- true
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
@@ -1,7 +1,7 @@
1
1
  module Resque
2
2
  module Plugins
3
3
  module Approval
4
- VERSION = '1.0.1'
4
+ VERSION = '1.2.0'
5
5
  end
6
6
  end
7
7
  end
@@ -25,4 +25,5 @@ Gem::Specification.new do |gem|
25
25
  gem.add_development_dependency 'rspec'
26
26
  gem.add_development_dependency 'guard'
27
27
  gem.add_development_dependency 'guard-rspec'
28
+ gem.add_development_dependency 'resque-scheduler'
28
29
  end
@@ -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(:approval_message => 'test message 2')
27
+ Job.enqueue_for_approval(:approval_timeout => 10)
28
+ Job.enqueue_for_approval(:approval_message => 'test message')
28
29
 
29
- keys = [{'id' => 0, 'approval_message' => 'test message 1'},
30
- {'id' => 1},
31
- {'id' => 2, 'approval_message' => 'test message 2'}]
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 (via symbol or string)" do
38
+ context "when a job requires approval" do
38
39
  it "calls enqueue_for_approval" do
39
- Job.should_receive(:enqueue_for_approval).twice.with({})
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 (via symbol)" do
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 => 'symbol test message')
75
+ Job.enqueue_for_approval(:approval_message => 'test message')
76
76
 
77
- key = '{"id":0,"approval_message":"symbol test 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 an approval message (via string)" do
85
- it "includes the message in the 'pending_jobs' hash entry" do
86
- Job.enqueue_for_approval('approval_message' => 'string test message')
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,"approval_message":"string test message"}'
89
- value = '{"class":"Job","args":[{}]}'
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 "moves the job from the approval queue to its normal queue" do
112
+ it "calls .remove_from_pending" do
98
113
  key = '{"id":0}'
99
114
 
100
- Resque.enqueue(Job, :requires_approval => true)
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
- Resque.size(:approval_required).should == 0
104
- Resque.size(:dummy).should == 1
126
+ Resque.size(:dummy).should == 1
127
+ end
105
128
  end
106
129
 
107
- it "deletes the entry in the 'pending_jobs' hash" do
108
- key = '{"id":0}'
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
- Resque.enqueue(Job, :requires_approval => true)
111
- Job.approve(key)
134
+ Job.enqueue_for_approval(:approval_timeout => 10)
135
+ Job.approve(key)
112
136
 
113
- Resque.redis.hget('pending_jobs', key).should be_nil
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 "deletes the job from the approval queue" do
147
+ it "calls .remove_from_pending" do
123
148
  key = '{"id":0}'
124
149
 
125
- Resque.enqueue(Job, :requires_approval => true)
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
- Resque.enqueue(Job, :requires_approval => true)
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
- Resque.enqueue(Job, :requires_approval => true)
144
- Job.reject(key)
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 false when key can not be found" do
150
- Job.reject('bad key').should == false
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
@@ -1,4 +1,6 @@
1
+ require 'rspec'
1
2
  require 'resque-approval'
3
+ require 'resque_scheduler'
2
4
 
3
5
  def start_redis
4
6
  redis_config = <<END
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.1
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-06 00:00:00.000000000 Z
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: &12083540 !ruby/object:Gem::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: *12083540
24
+ version_requirements: *11915740
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &12082920 !ruby/object:Gem::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: *12082920
35
+ version_requirements: *11910380
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &12082180 !ruby/object:Gem::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: *12082180
46
+ version_requirements: *11908520
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: guard
49
- requirement: &12080700 !ruby/object:Gem::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: *12080700
57
+ version_requirements: *11907760
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: guard-rspec
60
- requirement: &12078080 !ruby/object:Gem::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: *12078080
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."