resque-status 0.2.4 → 0.3.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/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source :rubygems
2
+
3
+ gem 'redisk', '>= 0.2.1'
4
+ gem 'resque', '>= 1.3.1'
5
+ gem 'uuid', '>= 2.0.2'
6
+ gem 'mocha', '>= 0.9.8'
7
+ gem 'shoulda', '>= 2.10.2'
8
+ gem 'jeweler'
data/Gemfile.lock ADDED
@@ -0,0 +1,51 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ git (1.2.5)
5
+ jeweler (1.6.4)
6
+ bundler (~> 1.0)
7
+ git (>= 1.2.5)
8
+ rake
9
+ json (1.4.6)
10
+ macaddr (1.5.0)
11
+ systemu (>= 2.4.0)
12
+ metaclass (0.0.1)
13
+ mocha (0.10.3)
14
+ metaclass (~> 0.0.1)
15
+ rack (1.4.0)
16
+ rack-protection (1.2.0)
17
+ rack
18
+ rake (0.9.2.2)
19
+ redis (2.2.2)
20
+ redis-namespace (1.1.0)
21
+ redis (< 3.0.0)
22
+ redisk (0.2.2)
23
+ redis (>= 0.1.1)
24
+ redis-namespace (>= 0.1.0)
25
+ resque (1.15.0)
26
+ json (~> 1.4.6)
27
+ redis-namespace (>= 0.10.0)
28
+ sinatra (>= 0.9.2)
29
+ vegas (~> 0.1.2)
30
+ shoulda (2.11.3)
31
+ sinatra (1.3.2)
32
+ rack (~> 1.3, >= 1.3.6)
33
+ rack-protection (~> 1.2)
34
+ tilt (~> 1.3, >= 1.3.3)
35
+ systemu (2.4.2)
36
+ tilt (1.3.3)
37
+ uuid (2.3.4)
38
+ macaddr (~> 1.0)
39
+ vegas (0.1.8)
40
+ rack (>= 1.0.0)
41
+
42
+ PLATFORMS
43
+ ruby
44
+
45
+ DEPENDENCIES
46
+ jeweler
47
+ mocha (>= 0.9.8)
48
+ redisk (>= 0.2.1)
49
+ resque (>= 1.3.1)
50
+ shoulda (>= 2.10.2)
51
+ uuid (>= 2.0.2)
data/README.rdoc CHANGED
@@ -19,41 +19,53 @@ Install the resque-status gem (which will pull in the dependencies).
19
19
 
20
20
  gem install resque-status
21
21
 
22
- To use with Rails, you can install as a plugin or add the gem to you're config:
22
+ To use with Rails 2.x, you can install as a plugin or add the gem to you're config:
23
23
 
24
24
  # environment.rb
25
- config.gem 'resque-status', :lib => 'resque/status'
26
-
25
+ config.gem 'resque-status'
26
+
27
+ With newer Rails add this to your Gemfile:
28
+
29
+ # Gemfile
30
+ gem 'resque-status'
31
+
27
32
  Then in an initializer:
28
33
 
29
34
  # config/initializers/resque.rb
30
- require 'resque/job_with_status'
31
-
32
35
  Resque.redis = "your/redis/socket" # default localhost:6379
33
- Resque::Status.expire_in = (24 * 60 * 60) # 24hrs in seconds
36
+ Resque::Plugins::Status::Hash.expire_in = (24 * 60 * 60) # 24hrs in seconds
37
+
38
+ == NOTES ABOUT UPGRADING TO >= v0.3
39
+
40
+ Even though this was one of the first resque plugins, later versions of resque added stricter plugin conventions
41
+ that resque-status did not completely conform to (See: https://github.com/defunkt/resque/blob/master/docs/PLUGINS.md)
42
+
43
+ Thanks to some work from @EugZol and @bukowskis v0.3 moved around some code to conform:
44
+
45
+ `Resque::Status` is now `Resque::Plugins::Status` and is now an `include`able module.
46
+ `Resque::Status.get/etc` have been moved to `Resque::Plugins::Status::Hash`
34
47
 
35
48
  == Usage
36
49
 
37
50
  The most direct way to use resque-status is to create your jobs using the
38
- Resque::JobWithStatus class. An example job would look something like:
51
+ Resque::Plugins::Status module. An example job would look something like:
39
52
 
40
- class SleepJob < Resque::JobWithStatus
53
+ class SleepJob
54
+ include Resque::Plugins::Status
41
55
 
42
56
  def perform
43
- total = options['length'].to_i || 1000
57
+ total = (options['length'] || 1000).to_i
44
58
  num = 0
45
59
  while num < total
46
60
  at(num, total, "At #{num} of #{total}")
47
61
  sleep(1)
48
62
  num += 1
49
63
  end
50
- completed
51
64
  end
52
65
 
53
66
  end
54
67
 
55
- Instead of normal Resque job classes, we inherit from the JobWithStatus class.
56
- Another major difference is that intead of implementing <tt>perform</tt> as a
68
+ One major difference is that intead of implementing <tt>perform</tt> as a
57
69
  class method, we do our job implementation within instances of the job class.
58
70
 
59
71
  In order to queue a SleepJob up, we also won't use <tt>Resque.enqueue</tt>, instead
@@ -67,9 +79,9 @@ instance as options['length'] (as you can see above).
67
79
 
68
80
  Now that we have a UUID its really easy to get the status:
69
81
 
70
- status = Resque::Status.get(job_id)
82
+ status = Resque::Plugins::Status::Hash.get(job_id)
71
83
 
72
- This returns a Resque::Status object, which is a Hash (with benefits).
84
+ This returns a Resque::Plugins::Status::Hash object, which is a Hash (with benefits).
73
85
 
74
86
  status.pct_complete #=> 0
75
87
  status.status #=> 'queued'
@@ -81,7 +93,7 @@ This returns a Resque::Status object, which is a Hash (with benefits).
81
93
  Once the worker reserves the job, the instance of SleepJob updates the status at
82
94
  each iteration using <tt>at()</tt>
83
95
 
84
- status = Resque::Status.get(job_id)
96
+ status = Resque::Plugins::Status::Hash.get(job_id)
85
97
  status.working? #=> true
86
98
  status.num #=> 5
87
99
  status.total => 100
@@ -92,7 +104,7 @@ the error is re-raised so that Resque can capture it.
92
104
 
93
105
  Its also possible to get a list of current/recent job statuses:
94
106
 
95
- Resque::Status.statuses #=> [#<Resque::Status>, ...]
107
+ Resque::Plugins::Status::Hash.statuses #=> [#<Resque::Plugins::Status::Hash>, ...]
96
108
 
97
109
  === Passing back data from the job
98
110
 
@@ -115,7 +127,7 @@ Because we're tracking UUIDs per instance, and we're checking in/updating the st
115
127
  on each iteration (using <tt>at</tt> or <tt>tick</tt>) we can kill specific jobs
116
128
  by UUID.
117
129
 
118
- Resque::Status.kill(job_id)
130
+ Resque::Plugins::Status::Hash.kill(job_id)
119
131
 
120
132
  The next time the job at job_id calls <tt>at</tt> or tick, it will raise a Killed
121
133
  error and set the status to killed.
@@ -126,7 +138,7 @@ Since Redis is RAM based, we probably don't want to keep these statuses around f
126
138
  (at least until @antirez releases the VM feature). By setting expire_in, all statuses
127
139
  and thier related keys will expire in expire_in seconds from the last time theyre updated:
128
140
 
129
- Resque::Status.expire_in = (60 * 60) # 1 hour
141
+ Resque::Plugins::Status::Hash.expire_in = (60 * 60) # 1 hour
130
142
 
131
143
  === resque-web
132
144
 
data/Rakefile CHANGED
@@ -1,15 +1,17 @@
1
+ $LOAD_PATH.unshift './lib'
2
+
1
3
  require 'rubygems'
2
4
  require 'rake'
3
- require File.join(File.expand_path('.'), 'lib/resque/status')
5
+ require 'resque-status'
4
6
  require 'resque/tasks'
5
7
 
6
8
  begin
7
9
  require 'jeweler'
8
10
  Jeweler::Tasks.new do |gem|
9
11
  gem.name = "resque-status"
10
- gem.version = Resque::Status::VERSION
12
+ gem.version = Resque::Plugins::Status::VERSION
11
13
  gem.summary = %Q{resque-status is an extension to the resque queue system that provides simple trackable jobs.}
12
- gem.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
+ gem.description = %Q{resque-status is an extension to the resque queue system that provides simple trackable jobs. It provides a Resque::Plugins::Status::Hash class which can set/get the statuses of jobs and a Resque::Plugins::Status class that when included provides easily trackable/killable jobs.}
13
15
  gem.email = "aaron@quirkey.com"
14
16
  gem.homepage = "http://github.com/quirkey/resque-status"
15
17
  gem.rubyforge_project = "quirkey"
@@ -46,7 +48,7 @@ rescue LoadError
46
48
  end
47
49
  end
48
50
 
49
- task :test => :check_dependencies
51
+ task :test
50
52
 
51
53
  task :default => :test
52
54
 
@@ -2,10 +2,11 @@ require 'resque/job_with_status' # in rails you would probably do this in an ini
2
2
 
3
3
  # sleeps for _length_ seconds updating the status every second
4
4
 
5
- class SleepJob < Resque::JobWithStatus
6
-
5
+ class SleepJob
6
+ include Resque::Plugins::Status
7
+
7
8
  def perform
8
- total = options['length'].to_i || 1000
9
+ total = options.has_key?('length') ? options['length'].to_i : 1000
9
10
  num = 0
10
11
  while num < total
11
12
  at(num, total, "At #{num} of #{total}")
@@ -14,22 +15,22 @@ class SleepJob < Resque::JobWithStatus
14
15
  end
15
16
  completed
16
17
  end
17
-
18
+
18
19
  end
19
20
 
20
21
 
21
22
  if __FILE__ == $0
22
23
  # Make sure you have a worker running
23
24
  # rake -rexamples/sleep_job.rb resque:work QUEUE=statused
24
-
25
+
25
26
  # running the job
26
27
  puts "Creating the SleepJob"
27
28
  job_id = SleepJob.create :length => 100
28
29
  puts "Got back #{job_id}"
29
-
30
+
30
31
  # check the status until its complete
31
- while status = Resque::Status.get(job_id) and !status.completed? && !status.failed?
32
+ while status = Resque::Plugins::Status::Hash.get(job_id) and !status.completed? && !status.failed?
32
33
  sleep 1
33
34
  puts status.inspect
34
35
  end
35
- end
36
+ end
data/init.rb CHANGED
@@ -1 +1 @@
1
- require 'resque/status'
1
+ require 'resque-status'
@@ -0,0 +1 @@
1
+ require 'resque/status'
@@ -1,202 +1,5 @@
1
- require 'resque/status'
2
-
3
1
  module Resque
4
-
5
- # JobWithStatus is a base class that you're jobs will inherit from.
6
- # It provides helper methods for updating the status/etc from within an
7
- # instance as well as class methods for creating and queuing the jobs.
8
- #
9
- # All you have to do to get this functionality is inherit from JobWithStatus
10
- # and then implement a <tt>perform<tt> method.
11
- #
12
- # For example:
13
- #
14
- # class ExampleJob < Resque::JobWithStatus
15
- #
16
- # def perform
17
- # num = options['num']
18
- # i = 0
19
- # while i < num
20
- # i += 1
21
- # at(i, num)
22
- # end
23
- # completed("Finished!")
24
- # end
25
- #
26
- # end
27
- #
28
- # This job would iterate num times updating the status as it goes. At the end
29
- # we update the status telling anyone listening to this job that its complete.
30
2
  class JobWithStatus
31
-
32
- # The error class raised when a job is killed
33
- class Killed < RuntimeError; end
34
-
35
- attr_reader :uuid, :options
36
-
37
- # The default queue is :statused, this can be ovveridden in the specific job
38
- # class to put the jobs on a specific worker queue
39
- def self.queue
40
- :statused
41
- end
42
-
43
- # used when displaying the Job in the resque-web UI and identifiyng the job
44
- # type by status. By default this is the name of the job class, but can be
45
- # ovveridden in the specific job class to present a more user friendly job
46
- # name
47
- def self.name
48
- self.to_s
49
- end
50
-
51
- # Create is the primary method for adding jobs to the queue. This would be
52
- # called on the job class to create a job of that type. Any options passed are
53
- # passed to the Job instance as a hash of options. It returns the UUID of the
54
- # job.
55
- #
56
- # == Example:
57
- #
58
- # class ExampleJob < Resque::JobWithStatus
59
- #
60
- # def perform
61
- # set_status "Hey I'm a job num #{options['num']}"
62
- # end
63
- #
64
- # end
65
- #
66
- # job_id = ExampleJob.create(:num => 100)
67
- #
68
- def self.create(options = {})
69
- self.enqueue(self, options)
70
- end
71
-
72
- # Adds a job of type <tt>klass<tt> to the queue with <tt>options<tt>.
73
- # Returns the UUID of the job
74
- def self.enqueue(klass, options = {})
75
- uuid = Resque::Status.create :options => options
76
- Resque.enqueue(klass, uuid, options)
77
- uuid
78
- end
79
-
80
- # This is the method called by Resque::Worker when processing jobs. It
81
- # creates a new instance of the job class and populates it with the uuid and
82
- # options.
83
- #
84
- # You should not override this method, rahter the <tt>perform</tt> instance method.
85
- def self.perform(uuid=nil, options = {})
86
- uuid ||= Resque::Status.generate_uuid
87
- instance = new(uuid, options)
88
- instance.safe_perform!
89
- instance
90
- end
91
-
92
- # Wrapper API to forward a Resque::Job creation API call into a JobWithStatus call.
93
- # This is needed to be used with resque scheduler
94
- # http://github.com/bvandenbos/resque-scheduler
95
- def self.scheduled(queue, klass, *args)
96
- create(*args)
97
- end
98
-
99
- # Create a new instance with <tt>uuid</tt> and <tt>options</tt>
100
- def initialize(uuid, options = {})
101
- @uuid = uuid
102
- @options = options
103
- end
104
-
105
- # Run by the Resque::Worker when processing this job. It wraps the <tt>perform</tt>
106
- # method ensuring that the final status of the job is set regardless of error.
107
- # If an error occurs within the job's work, it will set the status as failed and
108
- # re-raise the error.
109
- def safe_perform!
110
- set_status({'status' => 'working'})
111
- perform
112
- completed unless status && status.completed?
113
- on_success if respond_to?(:on_success)
114
- rescue Killed
115
- logger.info "Job #{self} Killed at #{Time.now}"
116
- Resque::Status.killed(uuid)
117
- on_killed if respond_to?(:on_killed)
118
- rescue => e
119
- logger.error e
120
- failed("The task failed because of an error: #{e}")
121
- if respond_to?(:on_failure)
122
- on_failure(e)
123
- else
124
- raise e
125
- end
126
- end
127
-
128
- # Returns a Redisk::Logger object scoped to this paticular job/uuid
129
- def logger
130
- @logger ||= Resque::Status.logger(uuid)
131
- end
132
-
133
- # Set the jobs status. Can take an array of strings or hashes that are merged
134
- # (in order) into a final status hash.
135
- def status=(new_status)
136
- Resque::Status.set(uuid, *new_status)
137
- end
138
-
139
- # get the Resque::Status object for the current uuid
140
- def status
141
- Resque::Status.get(uuid)
142
- end
143
-
144
- def name
145
- "#{self.class.name}(#{options.inspect unless options.empty?})"
146
- end
147
-
148
- # Checks against the kill list if this specific job instance should be killed
149
- # on the next iteration
150
- def should_kill?
151
- Resque::Status.should_kill?(uuid)
152
- end
153
-
154
- # set the status of the job for the current itteration. <tt>num</tt> and
155
- # <tt>total</tt> are passed to the status as well as any messages.
156
- # This will kill the job if it has been added to the kill list with
157
- # <tt>Resque::Status.kill()</tt>
158
- def at(num, total, *messages)
159
- tick({
160
- 'num' => num,
161
- 'total' => total
162
- }, *messages)
163
- end
164
-
165
- # sets the status of the job for the current itteration. You should use
166
- # the <tt>at</tt> method if you have actual numbers to track the iteration count.
167
- # This will kill the job if it has been added to the kill list with
168
- # <tt>Resque::Status.kill()</tt>
169
- def tick(*messages)
170
- kill! if should_kill?
171
- set_status({'status' => 'working'}, *messages)
172
- end
173
-
174
- # set the status to 'failed' passing along any additional messages
175
- def failed(*messages)
176
- set_status({'status' => 'failed'}, *messages)
177
- end
178
-
179
- # set the status to 'completed' passing along any addional messages
180
- def completed(*messages)
181
- set_status({
182
- 'status' => 'completed',
183
- 'message' => "Completed at #{Time.now}"
184
- }, *messages)
185
- end
186
-
187
- # kill the current job, setting the status to 'killed' and raising <tt>Killed</tt>
188
- def kill!
189
- set_status({
190
- 'status' => 'killed',
191
- 'message' => "Killed at #{Time.now}"
192
- })
193
- raise Killed
194
- end
195
-
196
- private
197
- def set_status(*args)
198
- self.status = [status, {'name' => self.name}, args].flatten
199
- end
200
-
3
+ include Resque::Plugins::Status
201
4
  end
202
5
  end