powerhome-resque-status 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0d9c0c0ab1c7036c3336d46117db310f73503b76d19ee9117dd4944668abc1a0
4
+ data.tar.gz: e9df86dd8599410cec3c1ce09e2afdc8785b36011fa921c9f2b11052a2b2a38d
5
+ SHA512:
6
+ metadata.gz: 022f4fedf4fd1ef8ceeb413a0ded6c9e118ae67ca78f0a3c3f044c79a0e950d274a4d5db4178022eeda6b14b04beab7c6f710bb0355502e871b8fefbcf2d70db
7
+ data.tar.gz: ba037b5c574172c20bd394955ed6a9c822c0cb717d8da027b9b1d0a1330dae9dfd459f380484a9254a956f07bc85b317332575660133b5886e63585a06f7f19c
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'resque', '~>1.19'
4
+
5
+ group :test do
6
+ gem 'mocha', '~>0.9'
7
+ gem 'minitest', '~> 5.5'
8
+ end
9
+
10
+ group :development do
11
+ gem 'jeweler'
12
+ end
@@ -0,0 +1,85 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ addressable (2.4.0)
5
+ builder (3.2.4)
6
+ descendants_tracker (0.0.4)
7
+ thread_safe (~> 0.3, >= 0.3.1)
8
+ faraday (0.9.2)
9
+ multipart-post (>= 1.2, < 3)
10
+ git (1.7.0)
11
+ rchardet (~> 1.8)
12
+ github_api (0.16.0)
13
+ addressable (~> 2.4.0)
14
+ descendants_tracker (~> 0.0.4)
15
+ faraday (~> 0.8, < 0.10)
16
+ hashie (>= 3.4)
17
+ mime-types (>= 1.16, < 3.0)
18
+ oauth2 (~> 1.0)
19
+ hashie (4.1.0)
20
+ highline (2.0.3)
21
+ jeweler (2.3.9)
22
+ builder
23
+ bundler
24
+ git (>= 1.2.5)
25
+ github_api (~> 0.16.0)
26
+ highline (>= 1.6.15)
27
+ nokogiri (>= 1.5.10)
28
+ psych
29
+ rake
30
+ rdoc
31
+ semver2
32
+ jwt (2.2.2)
33
+ metaclass (0.0.2)
34
+ mime-types (2.99.3)
35
+ mini_portile2 (2.4.0)
36
+ minitest (5.5.1)
37
+ mocha (0.14.0)
38
+ metaclass (~> 0.0.1)
39
+ multi_json (1.15.0)
40
+ multi_xml (0.6.0)
41
+ multipart-post (2.1.1)
42
+ nokogiri (1.10.10)
43
+ mini_portile2 (~> 2.4.0)
44
+ oauth2 (1.4.4)
45
+ faraday (>= 0.8, < 2.0)
46
+ jwt (>= 1.0, < 3.0)
47
+ multi_json (~> 1.3)
48
+ multi_xml (~> 0.5)
49
+ rack (>= 1.2, < 3)
50
+ psych (3.2.0)
51
+ rack (1.6.13)
52
+ rack-protection (1.2.0)
53
+ rack
54
+ rake (13.0.1)
55
+ rchardet (1.8.0)
56
+ rdoc (6.2.1)
57
+ redis (3.0.2)
58
+ redis-namespace (1.2.1)
59
+ redis (~> 3.0.0)
60
+ resque (1.23.0)
61
+ multi_json (~> 1.0)
62
+ redis-namespace (~> 1.0)
63
+ sinatra (>= 0.9.2)
64
+ vegas (~> 0.1.2)
65
+ semver2 (3.4.2)
66
+ sinatra (1.3.3)
67
+ rack (~> 1.3, >= 1.3.6)
68
+ rack-protection (~> 1.2)
69
+ tilt (~> 1.3, >= 1.3.3)
70
+ thread_safe (0.3.6)
71
+ tilt (1.3.3)
72
+ vegas (0.1.11)
73
+ rack (>= 1.0.0)
74
+
75
+ PLATFORMS
76
+ ruby
77
+
78
+ DEPENDENCIES
79
+ jeweler
80
+ minitest (~> 5.5)
81
+ mocha (~> 0.9)
82
+ resque (~> 1.19)
83
+
84
+ BUNDLED WITH
85
+ 2.1.4
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Aaron Quint
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,185 @@
1
+ = resque-status
2
+
3
+ resque-status is an extension to the resque queue system that provides simple trackable jobs.
4
+
5
+ == About
6
+
7
+ resque-status provides a set of simple classes that extend resque's default
8
+ functionality (with 0% monkey patching) to give apps a way to track specific
9
+ job instances and their status. It achieves this by giving job instances UUID's
10
+ and allowing the job instances to report their status from within their iterations.
11
+
12
+ == Installation
13
+
14
+ resque-status *requires Redis >= 1.1* (though I recommend getting the latest stable version).
15
+ You can download Redis here: http://code.google.com/p/redis/ or install it
16
+ using homebrew (brew install redis).
17
+
18
+ Install the resque-status gem (which will pull in the dependencies).
19
+
20
+ gem install resque-status
21
+
22
+ With newer Rails add this to your Gemfile:
23
+
24
+ # Gemfile
25
+ gem 'resque-status'
26
+
27
+ Then in an initializer:
28
+
29
+ # config/initializers/resque.rb
30
+ Resque.redis = "your/redis/socket" # default localhost:6379
31
+ Resque::Plugins::Status::Hash.expire_in = (24 * 60 * 60) # 24hrs in seconds
32
+
33
+ == Usage
34
+
35
+ The most direct way to use resque-status is to create your jobs using the
36
+ Resque::Plugins::Status module. An example job would look something like:
37
+
38
+ class SleepJob
39
+ include Resque::Plugins::Status
40
+
41
+ def perform
42
+ total = (options['length'] || 1000).to_i
43
+ total.times do |i|
44
+ num = i+1
45
+ at(num, total, "At #{num} of #{total}")
46
+ sleep(1)
47
+ end
48
+ end
49
+ end
50
+
51
+ One major difference is that instead of implementing <tt>perform</tt> as a
52
+ class method, we do our job implementation within instances of the job class.
53
+
54
+ In order to queue a SleepJob up, we also won't use <tt>Resque.enqueue</tt>, instead
55
+ we'll use the <tt>create</tt> class method which will wrap <tt>enqueue</tt> and
56
+ creating a unique id (UUID) for us to track the job with.
57
+
58
+ job_id = SleepJob.create(length: 100)
59
+
60
+ This will create a UUID enqueue the job and pass the :length option on the SleepJob
61
+ instance as options['length'] (as you can see above).
62
+
63
+ Now that we have a UUID its really easy to get the status:
64
+
65
+ status = Resque::Plugins::Status::Hash.get(job_id)
66
+
67
+ This returns a Resque::Plugins::Status::Hash object, which is a Hash (with benefits).
68
+
69
+ status.pct_complete #=> 0
70
+ status.status #=> 'queued'
71
+ status.queued? #=> true
72
+ status.working? #=> false
73
+ status.time #=> Time object
74
+ status.message #=> "Created at ..."
75
+
76
+ Once the worker reserves the job, the instance of SleepJob updates the status at
77
+ each iteration using <tt>at()</tt>
78
+
79
+ status = Resque::Plugins::Status::Hash.get(job_id)
80
+ status.working? #=> true
81
+ status.num #=> 5
82
+ status.total #=> 100
83
+ status.pct_complete #=> 5
84
+
85
+ If an error occurs within the job instance, the status is set to 'failed' and then
86
+ the error is re-raised so that Resque can capture it.
87
+
88
+ Its also possible to get a list of current/recent job statuses:
89
+
90
+ Resque::Plugins::Status::Hash.statuses #=> [#<Resque::Plugins::Status::Hash>, ...]
91
+
92
+ === Passing back data from the job
93
+
94
+ You may want to save data from inside the job to access it from outside the job.
95
+
96
+ A common use-case is web-triggered jobs that create files, later available for
97
+ download by the user.
98
+
99
+ A Status is actually just a hash, so inside a job you can do:
100
+
101
+ set_status(filename: "myfilename")
102
+
103
+ Also, all the status setting methods take any number of hash arguments. So you could do:
104
+
105
+ completed('filename' => '/myfilename')
106
+
107
+ === Kill! Kill! Kill!
108
+
109
+ Because we're tracking UUIDs per instance, and we're checking in/updating the status
110
+ on each iteration (using <tt>at</tt> or <tt>tick</tt>) we can kill specific jobs
111
+ by UUID.
112
+
113
+ Resque::Plugins::Status::Hash.kill(job_id)
114
+
115
+ The next time the job at job_id calls <tt>at</tt> or <tt>tick</tt>, it will raise a <tt>Killed</tt>
116
+ error and set the status to killed.
117
+
118
+ === Percent Complete and setting the message
119
+
120
+ Use <tt>at</tt> or <tt>tick</tt> to show progress in your job's <tt>perform</tt> function
121
+ (which is displayed on the resque-web status tab). This will also be where <tt>Killed</tt>
122
+ is raised if the job is killed.
123
+
124
+ at(steps_completed, total_steps, "${steps_completed} of #{total_steps} steps completed!")
125
+
126
+ === Expiration
127
+
128
+ Since Redis is RAM based, we probably don't want to keep these statuses around forever
129
+ (at least until @antirez releases the VM feature). By setting expire_in, all statuses
130
+ and their related keys will expire in expire_in seconds from the last time theyre updated:
131
+
132
+ Resque::Plugins::Status::Hash.expire_in = (60 * 60) # 1 hour
133
+ === Testing
134
+
135
+ Recent versions of Resque introduced `Resque.inline` which changes the behavior to
136
+ instead of enqueueing and performing jobs to just executing them inline. In Resque
137
+ itself this removes the dependency on a Redis, however, `Resque::Status` uses Redis
138
+ to store information about jobs, so though `inline` "works", you will still need
139
+ to use or mock a redis connection. You should be able to use a library like
140
+ https://github.com/causes/mock_redis alongside `inline` if you really want to
141
+ avoid Redis connections in your test.
142
+
143
+ === resque-web
144
+
145
+ Though the main purpose of these trackable jobs is to allow you to surface the status
146
+ of user created jobs through your apps' own UI, I've added a simple example UI
147
+ as a plugin to resque-web.
148
+
149
+ To use, you need to setup a resque-web config file:
150
+
151
+ # ~/resque_conf.rb
152
+ require 'resque/status_server'
153
+
154
+ Then start resque-web with your config:
155
+
156
+ resque-web ~/resque_conf.rb
157
+
158
+ This should launch resque-web in your browser and you should see a 'Statuses' tab.
159
+
160
+ http://img.skitch.com/20100119-k166xyijcjpkk6xtwnw3854a8g.jpg
161
+
162
+ == More
163
+
164
+ Source: http://github.com/quirkey/resque-status
165
+ API Docs: http://rdoc.info/projects/quirkey/resque-status
166
+ Examples: http://github.com/quirkey/resque-status/tree/master/examples
167
+ Resque: http://github.com/defunkt/resque
168
+
169
+ == Thanks
170
+
171
+ Resque is awesome, @defunkt needs a shout-out.
172
+
173
+ == Note on Patches/Pull Requests
174
+
175
+ * Fork the project.
176
+ * Make your feature addition or bug fix.
177
+ * Add tests for it. This is important so I don't break it in a
178
+ future version unintentionally.
179
+ * Commit, do not mess with rakefile, version, or history.
180
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
181
+ * Send me a pull request. Bonus points for topic branches.
182
+
183
+ == Copyright
184
+
185
+ Copyright (c) 2010 Aaron Quint. See LICENSE for details.
@@ -0,0 +1,48 @@
1
+ $LOAD_PATH.unshift './lib'
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+ require 'resque-status'
6
+ require 'resque/tasks'
7
+
8
+ begin
9
+ require 'jeweler'
10
+ Jeweler::Tasks.new do |gem|
11
+ gem.name = "powerhome-resque-status"
12
+ gem.version = Resque::Plugins::Status::VERSION
13
+ gem.summary = %Q{resque-status is an extension to the resque queue system that provides simple trackable 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.}
15
+ gem.email = "aaron@quirkey.com"
16
+ gem.homepage = "http://github.com/quirkey/resque-status"
17
+ gem.rubyforge_project = "quirkey"
18
+ gem.authors = ["Aaron Quint"]
19
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
20
+ end
21
+ Jeweler::RubygemsDotOrgTasks.new
22
+ rescue LoadError
23
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
24
+ end
25
+
26
+ require 'rake/testtask'
27
+ Rake::TestTask.new(:test) do |test|
28
+ test.libs << 'lib' << 'test'
29
+ test.pattern = 'test/**/test_*.rb'
30
+ test.verbose = true
31
+ end
32
+
33
+ begin
34
+ require 'rcov/rcovtask'
35
+ Rcov::RcovTask.new do |test|
36
+ test.libs << 'test'
37
+ test.pattern = 'test/**/test_*.rb'
38
+ test.verbose = true
39
+ end
40
+ rescue LoadError
41
+ task :rcov do
42
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
43
+ end
44
+ end
45
+
46
+ task :test
47
+
48
+ task :default => :test
@@ -0,0 +1,36 @@
1
+ require 'resque/job_with_status' # in rails you would probably do this in an initializer
2
+
3
+ # sleeps for _length_ seconds updating the status every second
4
+
5
+ class SleepJob
6
+ include Resque::Plugins::Status
7
+
8
+ def perform
9
+ total = options.has_key?('length') ? options['length'].to_i : 1000
10
+ num = 0
11
+ while num < total
12
+ at(num, total, "At #{num} of #{total}")
13
+ sleep(1)
14
+ num += 1
15
+ end
16
+ completed
17
+ end
18
+
19
+ end
20
+
21
+
22
+ if __FILE__ == $0
23
+ # Make sure you have a worker running
24
+ # rake -rexamples/sleep_job.rb resque:work QUEUE=statused
25
+
26
+ # running the job
27
+ puts "Creating the SleepJob"
28
+ job_id = SleepJob.create :length => 100
29
+ puts "Got back #{job_id}"
30
+
31
+ # check the status until its complete
32
+ while status = Resque::Plugins::Status::Hash.get(job_id) and !status.completed? && !status.failed?
33
+ sleep 1
34
+ puts status.inspect
35
+ end
36
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'resque-status'
@@ -0,0 +1 @@
1
+ require "#{File.dirname(__FILE__)}/resque/status"
@@ -0,0 +1,5 @@
1
+ module Resque
2
+ class JobWithStatus
3
+ include Resque::Plugins::Status
4
+ end
5
+ end
@@ -0,0 +1,254 @@
1
+ module Resque
2
+ module Plugins
3
+
4
+ # Resque::Plugins::Status is a module your jobs will include.
5
+ # It provides helper methods for updating the status/etc from within an
6
+ # instance as well as class methods for creating and queuing the jobs.
7
+ #
8
+ # All you have to do to get this functionality is include Resque::Plugins::Status
9
+ # and then implement a <tt>perform<tt> method.
10
+ #
11
+ # For example
12
+ #
13
+ # class ExampleJob
14
+ # include Resque::Plugins::Status
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
+ module Status
31
+ VERSION = '0.6.0'
32
+
33
+ STATUS_QUEUED = 'queued'
34
+ STATUS_WORKING = 'working'
35
+ STATUS_COMPLETED = 'completed'
36
+ STATUS_FAILED = 'failed'
37
+ STATUS_KILLED = 'killed'
38
+ STATUSES = [
39
+ STATUS_QUEUED,
40
+ STATUS_WORKING,
41
+ STATUS_COMPLETED,
42
+ STATUS_FAILED,
43
+ STATUS_KILLED
44
+ ].freeze
45
+
46
+ autoload :Hash, 'resque/plugins/status/hash'
47
+
48
+ # The error class raised when a job is killed
49
+ class Killed < RuntimeError; end
50
+ class NotANumber < RuntimeError; end
51
+
52
+ attr_reader :uuid, :options
53
+
54
+ def self.included(base)
55
+ base.extend(ClassMethods)
56
+ end
57
+
58
+ module ClassMethods
59
+
60
+ # The default queue is :statused, this can be ovveridden in the specific job
61
+ # class to put the jobs on a specific worker queue
62
+ def queue
63
+ :statused
64
+ end
65
+
66
+ # used when displaying the Job in the resque-web UI and identifiyng the job
67
+ # type by status. By default this is the name of the job class, but can be
68
+ # ovveridden in the specific job class to present a more user friendly job
69
+ # name
70
+ def name
71
+ self.to_s
72
+ end
73
+
74
+ # Create is the primary method for adding jobs to the queue. This would be
75
+ # called on the job class to create a job of that type. Any options passed are
76
+ # passed to the Job instance as a hash of options. It returns the UUID of the
77
+ # job.
78
+ #
79
+ # == Example:
80
+ #
81
+ # class ExampleJob
82
+ # include Resque::Plugins::Status
83
+ #
84
+ # def perform
85
+ # set_status "Hey I'm a job num #{options['num']}"
86
+ # end
87
+ #
88
+ # end
89
+ #
90
+ # job_id = ExampleJob.create(:num => 100)
91
+ #
92
+ def create(options = {})
93
+ self.enqueue(self, options)
94
+ end
95
+
96
+ # Adds a job of type <tt>klass<tt> to the queue with <tt>options<tt>.
97
+ #
98
+ # Returns the UUID of the job if the job was queued, or nil if the job was
99
+ # rejected by a before_enqueue hook.
100
+ def enqueue(klass, options = {})
101
+ self.enqueue_to(Resque.queue_from_class(klass) || queue, klass, options)
102
+ end
103
+
104
+ # Adds a job of type <tt>klass<tt> to a specified queue with <tt>options<tt>.
105
+ #
106
+ # Returns the UUID of the job if the job was queued, or nil if the job was
107
+ # rejected by a before_enqueue hook.
108
+ def enqueue_to(queue, klass, options = {})
109
+ uuid = Resque::Plugins::Status::Hash.generate_uuid
110
+ Resque::Plugins::Status::Hash.create uuid, :options => options
111
+
112
+ if Resque.enqueue_to(queue, klass, uuid, options)
113
+ uuid
114
+ else
115
+ Resque::Plugins::Status::Hash.remove(uuid)
116
+ nil
117
+ end
118
+ end
119
+
120
+ # Removes a job of type <tt>klass<tt> from the queue.
121
+ #
122
+ # The initially given options are retrieved from the status hash.
123
+ # (Resque needs the options to find the correct queue entry)
124
+ def dequeue(klass, uuid)
125
+ status = Resque::Plugins::Status::Hash.get(uuid)
126
+ Resque.dequeue(klass, uuid, status.options)
127
+ end
128
+
129
+ # This is the method called by Resque::Worker when processing jobs. It
130
+ # creates a new instance of the job class and populates it with the uuid and
131
+ # options.
132
+ #
133
+ # You should not override this method, rahter the <tt>perform</tt> instance method.
134
+ def perform(uuid=nil, options = {})
135
+ uuid ||= Resque::Plugins::Status::Hash.generate_uuid
136
+ instance = new(uuid, options)
137
+ instance.safe_perform!
138
+ instance
139
+ end
140
+
141
+ # Wrapper API to forward a Resque::Job creation API call into a Resque::Plugins::Status call.
142
+ # This is needed to be used with resque scheduler
143
+ # http://github.com/bvandenbos/resque-scheduler
144
+ def scheduled(queue, klass, *args)
145
+ self.enqueue_to(queue, self, *args)
146
+ end
147
+ end
148
+
149
+ # Create a new instance with <tt>uuid</tt> and <tt>options</tt>
150
+ def initialize(uuid, options = {})
151
+ @uuid = uuid
152
+ @options = options
153
+ end
154
+
155
+ # Run by the Resque::Worker when processing this job. It wraps the <tt>perform</tt>
156
+ # method ensuring that the final status of the job is set regardless of error.
157
+ # If an error occurs within the job's work, it will set the status as failed and
158
+ # re-raise the error.
159
+ def safe_perform!
160
+ set_status({'status' => STATUS_WORKING})
161
+ perform
162
+ if status && status.failed?
163
+ on_failure(status.message) if respond_to?(:on_failure)
164
+ return
165
+ elsif status && !status.completed?
166
+ completed
167
+ end
168
+ on_success if respond_to?(:on_success)
169
+ rescue Killed
170
+ Resque::Plugins::Status::Hash.killed(uuid)
171
+ on_killed if respond_to?(:on_killed)
172
+ rescue => e
173
+ failed("The task failed because of an error: #{e}")
174
+ if respond_to?(:on_failure)
175
+ on_failure(e)
176
+ else
177
+ raise e
178
+ end
179
+ end
180
+
181
+ # Set the jobs status. Can take an array of strings or hashes that are merged
182
+ # (in order) into a final status hash.
183
+ def status=(new_status)
184
+ Resque::Plugins::Status::Hash.set(uuid, *new_status)
185
+ end
186
+
187
+ # get the Resque::Plugins::Status::Hash object for the current uuid
188
+ def status
189
+ Resque::Plugins::Status::Hash.get(uuid)
190
+ end
191
+
192
+ def name
193
+ "#{self.class.name}(#{options.inspect unless options.empty?})"
194
+ end
195
+
196
+ # Checks against the kill list if this specific job instance should be killed
197
+ # on the next iteration
198
+ def should_kill?
199
+ Resque::Plugins::Status::Hash.should_kill?(uuid)
200
+ end
201
+
202
+ # set the status of the job for the current itteration. <tt>num</tt> and
203
+ # <tt>total</tt> are passed to the status as well as any messages.
204
+ # This will kill the job if it has been added to the kill list with
205
+ # <tt>Resque::Plugins::Status::Hash.kill()</tt>
206
+ def at(num, total, *messages)
207
+ if total.to_f <= 0.0
208
+ raise(NotANumber, "Called at() with total=#{total} which is not a number")
209
+ end
210
+ tick({
211
+ 'num' => num,
212
+ 'total' => total
213
+ }, *messages)
214
+ end
215
+
216
+ # sets the status of the job for the current itteration. You should use
217
+ # the <tt>at</tt> method if you have actual numbers to track the iteration count.
218
+ # This will kill the job if it has been added to the kill list with
219
+ # <tt>Resque::Plugins::Status::Hash.kill()</tt>
220
+ def tick(*messages)
221
+ kill! if should_kill?
222
+ set_status({'status' => STATUS_WORKING}, *messages)
223
+ end
224
+
225
+ # set the status to 'failed' passing along any additional messages
226
+ def failed(*messages)
227
+ set_status({'status' => STATUS_FAILED}, *messages)
228
+ end
229
+
230
+ # set the status to 'completed' passing along any addional messages
231
+ def completed(*messages)
232
+ set_status({
233
+ 'status' => STATUS_COMPLETED,
234
+ 'message' => "Completed at #{Time.now}"
235
+ }, *messages)
236
+ end
237
+
238
+ # kill the current job, setting the status to 'killed' and raising <tt>Killed</tt>
239
+ def kill!
240
+ set_status({
241
+ 'status' => STATUS_KILLED,
242
+ 'message' => "Killed at #{Time.now}"
243
+ })
244
+ raise Killed
245
+ end
246
+
247
+ private
248
+ def set_status(*args)
249
+ self.status = [status, {'name' => self.name}, args].flatten
250
+ end
251
+
252
+ end
253
+ end
254
+ end