resque-status 0.1.5 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +15 -0
- data/lib/resque/job_with_status.rb +15 -1
- data/lib/resque/server/views/statuses.erb +4 -0
- data/lib/resque/status.rb +54 -30
- data/lib/resque/status_server.rb +4 -1
- data/resque-status.gemspec +2 -2
- data/test/test_resque-status.rb +23 -0
- metadata +12 -4
data/README.rdoc
CHANGED
@@ -94,6 +94,21 @@ Its also possible to get a list of current/recent job statuses:
|
|
94
94
|
|
95
95
|
Resque::Status.statuses #=> [#<Resque::Status>, ...]
|
96
96
|
|
97
|
+
=== Passing back data from the job
|
98
|
+
|
99
|
+
You may want to save data from inside the job to access it from outside the job.
|
100
|
+
|
101
|
+
A common use-case is web-triggered jobs that create files, later available for
|
102
|
+
download by the user.
|
103
|
+
|
104
|
+
A Status is actually just a hash, so inside a job you can do:
|
105
|
+
|
106
|
+
status['filename'] = '/myfilename'
|
107
|
+
|
108
|
+
Also, all the status setting methods take any number of hash arguments. So you could do:
|
109
|
+
|
110
|
+
complete('filename' => '/myfilename')
|
111
|
+
|
97
112
|
=== Kill! Kill! Kill!
|
98
113
|
|
99
114
|
Because we're tracking UUIDs per instance, and we're checking in/updating the status
|
@@ -87,6 +87,13 @@ module Resque
|
|
87
87
|
instance.safe_perform!
|
88
88
|
instance
|
89
89
|
end
|
90
|
+
|
91
|
+
# Wrapper API to forward a Resque::Job creation API call into a JobWithStatus call.
|
92
|
+
# This is needed to be used with resque scheduler
|
93
|
+
# http://github.com/bvandenbos/resque-scheduler
|
94
|
+
def self.scheduled(queue, klass, *args)
|
95
|
+
create(args)
|
96
|
+
end
|
90
97
|
|
91
98
|
# Create a new instance with <tt>uuid</tt> and <tt>options</tt>
|
92
99
|
def initialize(uuid, options = {})
|
@@ -99,15 +106,22 @@ module Resque
|
|
99
106
|
# If an error occurs within the job's work, it will set the status as failed and
|
100
107
|
# re-raise the error.
|
101
108
|
def safe_perform!
|
109
|
+
set_status({'status' => 'working'})
|
102
110
|
perform
|
103
111
|
completed unless status && status.completed?
|
112
|
+
on_success if respond_to?(:on_success)
|
104
113
|
rescue Killed
|
105
114
|
logger.info "Job #{self} Killed at #{Time.now}"
|
106
115
|
Resque::Status.killed(uuid)
|
116
|
+
on_killed if respond_to?(:on_killed)
|
107
117
|
rescue => e
|
108
118
|
logger.error e
|
109
119
|
failed("The task failed because of an error: #{e}")
|
110
|
-
|
120
|
+
if respond_to?(:on_failure)
|
121
|
+
on_failure(e)
|
122
|
+
else
|
123
|
+
raise e
|
124
|
+
end
|
111
125
|
end
|
112
126
|
|
113
127
|
# Returns a Redisk::Logger object scoped to this paticular job/uuid
|
data/lib/resque/status.rb
CHANGED
@@ -3,11 +3,11 @@ require 'redisk'
|
|
3
3
|
require 'uuid'
|
4
4
|
|
5
5
|
module Resque
|
6
|
-
# Resque::Status is a Hash object that has helper methods for dealing with
|
7
|
-
# the common status attributes. It also has a number of class methods for
|
6
|
+
# Resque::Status is a Hash object that has helper methods for dealing with
|
7
|
+
# the common status attributes. It also has a number of class methods for
|
8
8
|
# creating/updating/retrieving status objects from Redis
|
9
9
|
class Status < Hash
|
10
|
-
VERSION = '0.
|
10
|
+
VERSION = '0.2.0'
|
11
11
|
|
12
12
|
extend Resque::Helpers
|
13
13
|
|
@@ -33,18 +33,18 @@ module Resque
|
|
33
33
|
val = Resque::Status.new(uuid, *messages)
|
34
34
|
redis.set(status_key(uuid), encode(val))
|
35
35
|
if expire_in
|
36
|
-
redis.expire(status_key(uuid), expire_in)
|
36
|
+
redis.expire(status_key(uuid), expire_in)
|
37
37
|
end
|
38
38
|
val
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
def self.clear
|
42
42
|
status_ids.each do |id|
|
43
43
|
redis.del(status_key(id))
|
44
44
|
redis.zrem(set_key, id)
|
45
45
|
end
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
# returns a Redisk::Logger scoped to the UUID. Any options passed are passed
|
49
49
|
# to the logger initialization.
|
50
50
|
#
|
@@ -54,53 +54,77 @@ module Resque
|
|
54
54
|
Redisk::Logger.new(logger_key(uuid), options)
|
55
55
|
end
|
56
56
|
|
57
|
+
def self.count
|
58
|
+
redis.zcard(set_key)
|
59
|
+
end
|
60
|
+
|
57
61
|
# Return <tt>num</tt> Resque::Status objects in reverse chronological order.
|
58
62
|
# By default returns the entire set.
|
59
|
-
|
60
|
-
|
63
|
+
# @param [Numeric] range_start The optional starting range
|
64
|
+
# @param [Numeric] range_end The optional ending range
|
65
|
+
# @example retuning the last 20 statuses
|
66
|
+
# Resque::Status.statuses(0, 20)
|
67
|
+
def self.statuses(range_start=nil, range_end=nil)
|
68
|
+
status_ids(range_start, range_end).collect do |id|
|
61
69
|
get(id)
|
62
70
|
end.compact
|
63
71
|
end
|
64
|
-
|
72
|
+
|
65
73
|
# Return the <tt>num</tt> most recent status/job UUIDs in reverse chronological order.
|
66
|
-
def self.status_ids(
|
67
|
-
|
74
|
+
def self.status_ids(range_start=nil, range_end=nil)
|
75
|
+
unless range_end && range_start
|
76
|
+
# Because we want a reverse chronological order, we need to get a range starting
|
77
|
+
# by the higest negative number.
|
78
|
+
redis.zrevrange(set_key, 0, -1) || []
|
79
|
+
else
|
80
|
+
# Because we want a reverse chronological order, we need to get a range starting
|
81
|
+
# by the higest negative number. The ordering is transparent from the API user's
|
82
|
+
# perspective so we need to convert the passed params
|
83
|
+
if range_start == 0
|
84
|
+
range_start = -1
|
85
|
+
else
|
86
|
+
range_end -= 1
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
(redis.zrevrange(set_key, -(range_end.abs), -(range_start.abs)) || []).reverse
|
91
|
+
end
|
68
92
|
end
|
69
|
-
|
93
|
+
|
70
94
|
# Kill the job at UUID on its next iteration this works by adding the UUID to a
|
71
|
-
# kill list (a.k.a. a list of jobs to be killed. Each iteration the job checks
|
95
|
+
# kill list (a.k.a. a list of jobs to be killed. Each iteration the job checks
|
72
96
|
# if it _should_ be killed by calling <tt>tick</tt> or <tt>at</tt>. If so, it raises
|
73
97
|
# a <tt>Resque::JobWithStatus::Killed</tt> error and sets the status to 'killed'.
|
74
|
-
def self.kill(uuid)
|
98
|
+
def self.kill(uuid)
|
75
99
|
redis.sadd(kill_key, uuid)
|
76
100
|
end
|
77
|
-
|
101
|
+
|
78
102
|
# Remove the job at UUID from the kill list
|
79
103
|
def self.killed(uuid)
|
80
104
|
redis.srem(kill_key, uuid)
|
81
105
|
end
|
82
|
-
|
106
|
+
|
83
107
|
# Return the UUIDs of the jobs on the kill list
|
84
108
|
def self.kill_ids
|
85
109
|
redis.smembers(kill_key)
|
86
110
|
end
|
87
|
-
|
111
|
+
|
88
112
|
# Check whether a job with UUID is on the kill list
|
89
113
|
def self.should_kill?(uuid)
|
90
114
|
redis.sismember(kill_key, uuid)
|
91
115
|
end
|
92
|
-
|
116
|
+
|
93
117
|
# The time in seconds that jobs and statuses should expire from Redis (after
|
94
118
|
# the last time they are touched/updated)
|
95
119
|
def self.expire_in
|
96
120
|
@expire_in
|
97
121
|
end
|
98
|
-
|
122
|
+
|
99
123
|
# Set the <tt>expire_in</tt> time in seconds
|
100
124
|
def self.expire_in=(seconds)
|
101
125
|
@expire_in = seconds.nil? ? nil : seconds.to_i
|
102
126
|
end
|
103
|
-
|
127
|
+
|
104
128
|
def self.status_key(uuid)
|
105
129
|
"status:#{uuid}"
|
106
130
|
end
|
@@ -111,7 +135,7 @@ module Resque
|
|
111
135
|
|
112
136
|
def self.kill_key
|
113
137
|
"_kill"
|
114
|
-
end
|
138
|
+
end
|
115
139
|
|
116
140
|
def self.logger_key(uuid)
|
117
141
|
"_log:#{uuid}"
|
@@ -122,7 +146,7 @@ module Resque
|
|
122
146
|
end
|
123
147
|
|
124
148
|
def self.hash_accessor(name, options = {})
|
125
|
-
options[:default] ||= nil
|
149
|
+
options[:default] ||= nil
|
126
150
|
coerce = options[:coerce] ? ".#{options[:coerce]}" : ""
|
127
151
|
module_eval <<-EOT
|
128
152
|
def #{name}
|
@@ -151,10 +175,10 @@ module Resque
|
|
151
175
|
|
152
176
|
hash_accessor :num
|
153
177
|
hash_accessor :total
|
154
|
-
|
178
|
+
|
155
179
|
# Create a new Resque::Status object. If multiple arguments are passed
|
156
180
|
# it is assumed the first argument is the UUID and the rest are status objects.
|
157
|
-
# All arguments are subsequentily merged in order. Strings are assumed to
|
181
|
+
# All arguments are subsequentily merged in order. Strings are assumed to
|
158
182
|
# be messages.
|
159
183
|
def initialize(*args)
|
160
184
|
super nil
|
@@ -169,7 +193,7 @@ module Resque
|
|
169
193
|
end
|
170
194
|
self.replace(status_hash)
|
171
195
|
end
|
172
|
-
|
196
|
+
|
173
197
|
# calculate the % completion of the job based on <tt>status</tt>, <tt>num</tt>
|
174
198
|
# and <tt>total</tt>
|
175
199
|
def pct_complete
|
@@ -182,7 +206,7 @@ module Resque
|
|
182
206
|
(((num || 0).to_f / t.to_f) * 100).to_i
|
183
207
|
end
|
184
208
|
end
|
185
|
-
|
209
|
+
|
186
210
|
# Return the time of the status initialization. If set returns a <tt>Time</tt>
|
187
211
|
# object, otherwise returns nil
|
188
212
|
def time
|
@@ -191,22 +215,22 @@ module Resque
|
|
191
215
|
|
192
216
|
STATUSES.each do |status|
|
193
217
|
define_method("#{status}?") do
|
194
|
-
self['status'] === status
|
218
|
+
self['status'] === status
|
195
219
|
end
|
196
220
|
end
|
197
|
-
|
221
|
+
|
198
222
|
# Can the job be killed? 'failed', 'completed', and 'killed' jobs cant be killed
|
199
223
|
# (for pretty obvious reasons)
|
200
224
|
def killable?
|
201
225
|
!['failed', 'completed', 'killed'].include?(self.status)
|
202
226
|
end
|
203
|
-
|
227
|
+
|
204
228
|
unless method_defined?(:to_json)
|
205
229
|
def to_json(*args)
|
206
230
|
json
|
207
231
|
end
|
208
232
|
end
|
209
|
-
|
233
|
+
|
210
234
|
# Return a JSON representation of the current object.
|
211
235
|
def json
|
212
236
|
h = self.dup
|
data/lib/resque/status_server.rb
CHANGED
@@ -8,7 +8,10 @@ module Resque
|
|
8
8
|
def self.registered(app)
|
9
9
|
|
10
10
|
app.get '/statuses' do
|
11
|
-
@
|
11
|
+
@start = params[:start].to_i
|
12
|
+
@end = @start + (params[:per_page] || 50)
|
13
|
+
@statuses = Resque::Status.statuses(@start, @end)
|
14
|
+
@size = @statuses.size
|
12
15
|
status_view(:statuses)
|
13
16
|
end
|
14
17
|
|
data/resque-status.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{resque-status}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Aaron Quint"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-10-11}
|
13
13
|
s.description = %q{resque-status is an extension to the resque queue system that provides simple trackable jobs. It provides a Resque::Status class which can set/get the statuses of jobs and a Resque::JobWithStatus class that when subclassed provides easily trackable/killable jobs.}
|
14
14
|
s.email = %q{aaron@quirkey.com}
|
15
15
|
s.extra_rdoc_files = [
|
data/test/test_resque-status.rb
CHANGED
@@ -87,8 +87,21 @@ class TestResqueStatus < Test::Unit::TestCase
|
|
87
87
|
end
|
88
88
|
|
89
89
|
context ".status_ids" do
|
90
|
+
|
91
|
+
setup do
|
92
|
+
@uuids = []
|
93
|
+
30.times{ Resque::Status.create }
|
94
|
+
end
|
95
|
+
|
90
96
|
should "return an array of job ids" do
|
91
97
|
assert Resque::Status.status_ids.is_a?(Array)
|
98
|
+
assert_equal 32, Resque::Status.status_ids.size # 30 + 2
|
99
|
+
end
|
100
|
+
|
101
|
+
should "let you paginate through the statuses" do
|
102
|
+
assert_equal Resque::Status.status_ids.reverse[0, 10], Resque::Status.status_ids(0, 10)
|
103
|
+
assert_equal Resque::Status.status_ids.reverse[9, 10], Resque::Status.status_ids(10, 20)
|
104
|
+
# assert_equal Resque::Status.status_ids.reverse[0, 10], Resque::Status.status_ids(0, 10)
|
92
105
|
end
|
93
106
|
end
|
94
107
|
|
@@ -102,6 +115,16 @@ class TestResqueStatus < Test::Unit::TestCase
|
|
102
115
|
|
103
116
|
end
|
104
117
|
|
118
|
+
# context ".count" do
|
119
|
+
#
|
120
|
+
# should "return a count of statuses" do
|
121
|
+
# statuses = Resque::Status.statuses
|
122
|
+
# assert_equal 2, statuses.size
|
123
|
+
# assert_equal statuses.size, Resque::Status.count
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# end
|
127
|
+
|
105
128
|
context ".logger" do
|
106
129
|
setup do
|
107
130
|
@logger = Resque::Status.logger(@uuid)
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-status
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Aaron Quint
|
@@ -14,7 +15,7 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-
|
18
|
+
date: 2010-10-11 00:00:00 -07:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
@@ -25,6 +26,7 @@ dependencies:
|
|
25
26
|
requirements:
|
26
27
|
- - ">="
|
27
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 11
|
28
30
|
segments:
|
29
31
|
- 2
|
30
32
|
- 0
|
@@ -40,6 +42,7 @@ dependencies:
|
|
40
42
|
requirements:
|
41
43
|
- - ">="
|
42
44
|
- !ruby/object:Gem::Version
|
45
|
+
hash: 25
|
43
46
|
segments:
|
44
47
|
- 1
|
45
48
|
- 3
|
@@ -55,6 +58,7 @@ dependencies:
|
|
55
58
|
requirements:
|
56
59
|
- - ">="
|
57
60
|
- !ruby/object:Gem::Version
|
61
|
+
hash: 21
|
58
62
|
segments:
|
59
63
|
- 0
|
60
64
|
- 2
|
@@ -70,6 +74,7 @@ dependencies:
|
|
70
74
|
requirements:
|
71
75
|
- - ">="
|
72
76
|
- !ruby/object:Gem::Version
|
77
|
+
hash: 35
|
73
78
|
segments:
|
74
79
|
- 2
|
75
80
|
- 10
|
@@ -85,6 +90,7 @@ dependencies:
|
|
85
90
|
requirements:
|
86
91
|
- - ">="
|
87
92
|
- !ruby/object:Gem::Version
|
93
|
+
hash: 43
|
88
94
|
segments:
|
89
95
|
- 0
|
90
96
|
- 9
|
@@ -134,6 +140,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
134
140
|
requirements:
|
135
141
|
- - ">="
|
136
142
|
- !ruby/object:Gem::Version
|
143
|
+
hash: 3
|
137
144
|
segments:
|
138
145
|
- 0
|
139
146
|
version: "0"
|
@@ -142,6 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
149
|
requirements:
|
143
150
|
- - ">="
|
144
151
|
- !ruby/object:Gem::Version
|
152
|
+
hash: 3
|
145
153
|
segments:
|
146
154
|
- 0
|
147
155
|
version: "0"
|