resque-status 0.2.1 → 0.2.2

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.
@@ -1,18 +1,18 @@
1
1
  require 'resque/status'
2
2
 
3
3
  module Resque
4
-
4
+
5
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
6
+ # It provides helper methods for updating the status/etc from within an
7
7
  # instance as well as class methods for creating and queuing the jobs.
8
- #
8
+ #
9
9
  # All you have to do to get this functionality is inherit from JobWithStatus
10
10
  # and then implement a <tt>perform<tt> method.
11
- #
11
+ #
12
12
  # For example:
13
- #
13
+ #
14
14
  # class ExampleJob < Resque::JobWithStatus
15
- #
15
+ #
16
16
  # def perform
17
17
  # num = options['num']
18
18
  # i = 0
@@ -22,62 +22,62 @@ module Resque
22
22
  # end
23
23
  # completed("Finished!")
24
24
  # end
25
- #
25
+ #
26
26
  # end
27
- #
27
+ #
28
28
  # This job would iterate num times updating the status as it goes. At the end
29
29
  # we update the status telling anyone listening to this job that its complete.
30
30
  class JobWithStatus
31
-
31
+
32
32
  # The error class raised when a job is killed
33
33
  class Killed < RuntimeError; end
34
-
34
+
35
35
  attr_reader :uuid, :options
36
-
36
+
37
37
  # The default queue is :statused, this can be ovveridden in the specific job
38
38
  # class to put the jobs on a specific worker queue
39
39
  def self.queue
40
40
  :statused
41
41
  end
42
-
42
+
43
43
  # used when displaying the Job in the resque-web UI and identifiyng the job
44
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
45
+ # ovveridden in the specific job class to present a more user friendly job
46
46
  # name
47
47
  def self.name
48
48
  self.to_s
49
49
  end
50
-
51
- # Create is the primary method for adding jobs to the queue. This would be
50
+
51
+ # Create is the primary method for adding jobs to the queue. This would be
52
52
  # called on the job class to create a job of that type. Any options passed are
53
53
  # passed to the Job instance as a hash of options. It returns the UUID of the
54
54
  # job.
55
55
  #
56
56
  # == Example:
57
- #
57
+ #
58
58
  # class ExampleJob < Resque::JobWithStatus
59
- #
59
+ #
60
60
  # def perform
61
61
  # set_status "Hey I'm a job num #{options['num']}"
62
62
  # end
63
- #
63
+ #
64
64
  # end
65
- #
65
+ #
66
66
  # job_id = ExampleJob.create(:num => 100)
67
- #
67
+ #
68
68
  def self.create(options = {})
69
69
  self.enqueue(self, options)
70
70
  end
71
-
71
+
72
72
  # Adds a job of type <tt>klass<tt> to the queue with <tt>options<tt>.
73
73
  # Returns the UUID of the job
74
74
  def self.enqueue(klass, options = {})
75
- uuid = Resque::Status.create
75
+ uuid = Resque::Status.create :options => options
76
76
  Resque.enqueue(klass, uuid, options)
77
77
  uuid
78
78
  end
79
79
 
80
- # This is the method called by Resque::Worker when processing jobs. It
80
+ # This is the method called by Resque::Worker when processing jobs. It
81
81
  # creates a new instance of the job class and populates it with the uuid and
82
82
  # options.
83
83
  #
@@ -88,7 +88,7 @@ module Resque
88
88
  instance.safe_perform!
89
89
  instance
90
90
  end
91
-
91
+
92
92
  # Wrapper API to forward a Resque::Job creation API call into a JobWithStatus call.
93
93
  # This is needed to be used with resque scheduler
94
94
  # http://github.com/bvandenbos/resque-scheduler
@@ -101,10 +101,10 @@ module Resque
101
101
  @uuid = uuid
102
102
  @options = options
103
103
  end
104
-
104
+
105
105
  # Run by the Resque::Worker when processing this job. It wraps the <tt>perform</tt>
106
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
107
+ # If an error occurs within the job's work, it will set the status as failed and
108
108
  # re-raise the error.
109
109
  def safe_perform!
110
110
  set_status({'status' => 'working'})
@@ -135,14 +135,14 @@ module Resque
135
135
  def status=(new_status)
136
136
  Resque::Status.set(uuid, *new_status)
137
137
  end
138
-
138
+
139
139
  # get the Resque::Status object for the current uuid
140
140
  def status
141
141
  Resque::Status.get(uuid)
142
142
  end
143
143
 
144
144
  def name
145
- self.class.name
145
+ "#{self.class.name}(#{options unless options.empty?})"
146
146
  end
147
147
 
148
148
  # Checks against the kill list if this specific job instance should be killed
@@ -151,31 +151,31 @@ module Resque
151
151
  Resque::Status.should_kill?(uuid)
152
152
  end
153
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
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
157
  # <tt>Resque::Status.kill()</tt>
158
158
  def at(num, total, *messages)
159
159
  tick({
160
- 'num' => num,
160
+ 'num' => num,
161
161
  'total' => total
162
162
  }, *messages)
163
163
  end
164
-
165
- # sets the status of the job for the current itteration. You should use
164
+
165
+ # sets the status of the job for the current itteration. You should use
166
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
167
+ # This will kill the job if it has been added to the kill list with
168
168
  # <tt>Resque::Status.kill()</tt>
169
169
  def tick(*messages)
170
170
  kill! if should_kill?
171
171
  set_status({'status' => 'working'}, *messages)
172
172
  end
173
-
173
+
174
174
  # set the status to 'failed' passing along any additional messages
175
175
  def failed(*messages)
176
176
  set_status({'status' => 'failed'}, *messages)
177
177
  end
178
-
178
+
179
179
  # set the status to 'completed' passing along any addional messages
180
180
  def completed(*messages)
181
181
  set_status({
@@ -183,7 +183,7 @@ module Resque
183
183
  'message' => "Completed at #{Time.now}"
184
184
  }, *messages)
185
185
  end
186
-
186
+
187
187
  # kill the current job, setting the status to 'killed' and raising <tt>Killed</tt>
188
188
  def kill!
189
189
  set_status({
@@ -192,11 +192,11 @@ module Resque
192
192
  })
193
193
  raise Killed
194
194
  end
195
-
195
+
196
196
  private
197
197
  def set_status(*args)
198
198
  self.status = [status, {'name' => self.name}, args].flatten
199
199
  end
200
-
200
+
201
201
  end
202
- end
202
+ end
data/lib/resque/status.rb CHANGED
@@ -7,15 +7,15 @@ module Resque
7
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.2.1'
10
+ VERSION = '0.2.2'
11
11
 
12
12
  extend Resque::Helpers
13
13
 
14
14
  # Create a status, generating a new UUID, passing the message to the status
15
15
  # Returns the UUID of the new status.
16
- def self.create(message = nil)
16
+ def self.create(*messages)
17
17
  uuid = generate_uuid
18
- set(uuid, message)
18
+ set(uuid, *messages)
19
19
  redis.zadd(set_key, Time.now.to_i, uuid)
20
20
  redis.zremrangebyscore(set_key, 0, Time.now.to_i - @expire_in) if @expire_in
21
21
  uuid
@@ -172,6 +172,7 @@ module Resque
172
172
  hash_accessor :status
173
173
  hash_accessor :message
174
174
  hash_accessor :time
175
+ hash_accessor :options
175
176
 
176
177
  hash_accessor :num
177
178
  hash_accessor :total
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{resque-status}
8
- s.version = "0.2.1"
8
+ s.version = "0.2.2"
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{2011-01-14}
12
+ s.date = %q{2011-02-09}
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/redis-test.conf CHANGED
@@ -128,5 +128,3 @@ glueoutputbuf yes
128
128
  # WARNING: object sharing is experimental, don't enable this feature
129
129
  # in production before of Redis 1.0-stable. Still please try this feature in
130
130
  # your development environment so that we can test it better.
131
- shareobjects no
132
- shareobjectspoolsize 1024
@@ -1,87 +1,87 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class TestResqueJobWithStatus < Test::Unit::TestCase
4
-
4
+
5
5
  context "Resque::JobWithStatus" do
6
6
  setup do
7
7
  Resque.redis.flushall
8
8
  end
9
-
9
+
10
10
  context ".create" do
11
11
  setup do
12
12
  @uuid = WorkingJob.create('num' => 100)
13
13
  end
14
-
14
+
15
15
  should "add the job to the queue" do
16
16
  assert_equal 1, Resque.size(:statused)
17
17
  end
18
-
18
+
19
19
  should "set the queued object to the current class" do
20
20
  job = Resque.pop(:statused)
21
21
  assert_equal @uuid, job['args'].first
22
22
  assert_equal "WorkingJob", job['class']
23
23
  end
24
-
24
+
25
25
  should "add the uuid to the statuses" do
26
26
  assert_contains Resque::Status.status_ids, @uuid
27
27
  end
28
-
28
+
29
29
  should "return a UUID" do
30
30
  assert_match(/^\w{32}$/, @uuid)
31
31
  end
32
-
32
+
33
33
  end
34
-
34
+
35
35
  context ".enqueue" do
36
36
  setup do
37
37
  @uuid = Resque::JobWithStatus.enqueue(WorkingJob, :num => 100)
38
38
  @payload = Resque.pop(:statused)
39
39
  end
40
-
40
+
41
41
  should "add the job with the specific class to the queue" do
42
42
  assert_equal "WorkingJob", @payload['class']
43
43
  end
44
-
44
+
45
45
  should "add the arguments to the options hash" do
46
46
  assert_equal @uuid, @payload['args'].first
47
47
  end
48
-
48
+
49
49
  should "add the uuid to the statuses" do
50
50
  assert_contains Resque::Status.status_ids, @uuid
51
51
  end
52
-
52
+
53
53
  should "return UUID" do
54
54
  assert_match(/^\w{32}$/, @uuid)
55
55
  end
56
-
56
+
57
57
  end
58
-
58
+
59
59
  context ".perform" do
60
60
  setup do
61
61
  @uuid = WorkingJob.create(:num => 100)
62
62
  @payload = Resque.pop(:statused)
63
63
  @performed = WorkingJob.perform(*@payload['args'])
64
64
  end
65
-
65
+
66
66
  should "load load a new instance of the klass" do
67
67
  assert @performed.is_a?(WorkingJob)
68
68
  end
69
-
69
+
70
70
  should "set the uuid" do
71
71
  assert_equal @uuid, @performed.uuid
72
72
  end
73
-
73
+
74
74
  should "set the status" do
75
75
  assert @performed.status.is_a?(Resque::Status)
76
- assert_equal 'WorkingJob', @performed.status.name
76
+ assert_equal 'WorkingJob({"num"=>100})', @performed.status.name
77
77
  end
78
-
78
+
79
79
  before_should "call perform on the inherited class" do
80
80
  WorkingJob.any_instance.expects(:perform).once
81
81
  end
82
-
82
+
83
83
  end
84
-
84
+
85
85
  context "killing a job" do
86
86
  setup do
87
87
  @uuid = KillableJob.create(:num => 100)
@@ -91,74 +91,74 @@ class TestResqueJobWithStatus < Test::Unit::TestCase
91
91
  @performed = KillableJob.perform(*@payload['args'])
92
92
  @status = Resque::Status.get(@uuid)
93
93
  end
94
-
94
+
95
95
  should "set the status to killed" do
96
96
  assert_equal 'killed', @status.status
97
97
  assert @status.killed?
98
98
  assert !@status.completed?
99
99
  end
100
-
100
+
101
101
  should "only perform iterations up to kill" do
102
102
  assert_equal 1, Resque.redis.get("#{@uuid}:iterations").to_i
103
103
  end
104
-
104
+
105
105
  should "not persist the kill key" do
106
106
  assert_does_not_contain Resque::Status.kill_ids, @uuid
107
107
  end
108
108
  end
109
-
109
+
110
110
  context "with an invoked job" do
111
111
  setup do
112
112
  @job = WorkingJob.new('123', {'num' => 100})
113
113
  end
114
-
114
+
115
115
  context "#at" do
116
116
  setup do
117
117
  @job.at(50, 100, "At 50%")
118
118
  end
119
-
119
+
120
120
  should "calculate percent" do
121
121
  assert_equal 50, @job.status.pct_complete
122
122
  end
123
-
123
+
124
124
  should "set status" do
125
125
  assert_equal 'working', @job.status.status
126
126
  end
127
-
127
+
128
128
  should "save message" do
129
129
  assert_equal "At 50%", @job.status.message
130
130
  end
131
131
  end
132
-
132
+
133
133
  context "#failed" do
134
134
  setup do
135
135
  @job.failed("OOOOPS!")
136
136
  end
137
-
137
+
138
138
  should "set status" do
139
139
  assert_equal 'failed', @job.status.status
140
140
  end
141
-
141
+
142
142
  should "set message" do
143
143
  assert_equal "OOOOPS!", @job.status.message
144
144
  end
145
145
  end
146
-
146
+
147
147
  context "#completed" do
148
148
  setup do
149
149
  @job.completed
150
150
  end
151
-
151
+
152
152
  should "set status" do
153
153
  assert_equal 'completed', @job.status.status
154
154
  end
155
-
155
+
156
156
  should "set message" do
157
157
  assert_match(/complete/i, @job.status.message)
158
158
  end
159
-
159
+
160
160
  end
161
-
161
+
162
162
  context "#safe_perform!" do
163
163
  setup do
164
164
  @job = ErrorJob.new("123")
@@ -166,15 +166,15 @@ class TestResqueJobWithStatus < Test::Unit::TestCase
166
166
  @job.safe_perform!
167
167
  end
168
168
  end
169
-
169
+
170
170
  should "set status as failed" do
171
171
  assert_equal 'failed', @job.status.status
172
172
  end
173
-
173
+
174
174
  end
175
-
175
+
176
176
  end
177
-
177
+
178
178
  end
179
-
180
- end
179
+
180
+ end
@@ -10,36 +10,36 @@ class TestResqueStatus < Test::Unit::TestCase
10
10
  Resque::Status.set(@uuid, "my status")
11
11
  @uuid_with_json = Resque::Status.create({"im" => "json"})
12
12
  end
13
-
14
- context ".get" do
13
+
14
+ context ".get" do
15
15
  should "return the status as a Resque::Status for the uuid" do
16
16
  status = Resque::Status.get(@uuid)
17
17
  assert status.is_a?(Resque::Status)
18
18
  assert_equal 'my status', status.message
19
19
  end
20
-
20
+
21
21
  should "return false if the status is not set" do
22
22
  assert !Resque::Status.get('whu')
23
23
  end
24
-
24
+
25
25
  should "decode encoded json" do
26
26
  assert_equal("json", Resque::Status.get(@uuid_with_json)['im'])
27
27
  end
28
28
  end
29
-
29
+
30
30
  context ".set" do
31
-
31
+
32
32
  should "set the status for the uuid" do
33
33
  assert Resque::Status.set(@uuid, "updated")
34
34
  assert_equal "updated", Resque::Status.get(@uuid).message
35
35
  end
36
-
36
+
37
37
  should "return the status" do
38
38
  assert Resque::Status.set(@uuid, "updated").is_a?(Resque::Status)
39
39
  end
40
-
40
+
41
41
  end
42
-
42
+
43
43
  context ".create" do
44
44
  should "add an item to a key set" do
45
45
  before = Resque::Status.status_ids.length
@@ -47,18 +47,18 @@ class TestResqueStatus < Test::Unit::TestCase
47
47
  after = Resque::Status.status_ids.length
48
48
  assert_equal 1, after - before
49
49
  end
50
-
50
+
51
51
  should "return a uuid" do
52
52
  assert_match(/^\w{32}$/, Resque::Status.create)
53
53
  end
54
-
54
+
55
55
  should "store any status passed" do
56
56
  uuid = Resque::Status.create("initial status")
57
57
  status = Resque::Status.get(uuid)
58
58
  assert status.is_a?(Resque::Status)
59
59
  assert_equal "initial status", status.message
60
60
  end
61
-
61
+
62
62
  should "expire keys if expire_in is set" do
63
63
  Resque::Status.expire_in = 1
64
64
  uuid = Resque::Status.create("new status")
@@ -69,77 +69,85 @@ class TestResqueStatus < Test::Unit::TestCase
69
69
  assert_does_not_contain Resque::Status.status_ids, uuid
70
70
  assert_nil Resque::Status.get(uuid)
71
71
  end
72
+
73
+ should "store the options for the job created" do
74
+ uuid = Resque::Status.create("new", :options => {'test' => '123'})
75
+ assert uuid
76
+ status = Resque::Status.get(uuid)
77
+ assert status.is_a?(Resque::Status)
78
+ assert_equal '123', status.options['test']
79
+ end
72
80
  end
73
-
81
+
74
82
  context ".clear" do
75
83
  setup do
76
84
  Resque::Status.clear
77
85
  end
78
-
86
+
79
87
  should "clear any statuses" do
80
88
  assert_nil Resque::Status.get(@uuid)
81
89
  end
82
-
90
+
83
91
  should "clear any recent statuses" do
84
92
  assert Resque::Status.status_ids.empty?
85
93
  end
86
-
94
+
87
95
  end
88
-
96
+
89
97
  context ".status_ids" do
90
-
98
+
91
99
  setup do
92
100
  @uuids = []
93
101
  30.times{ Resque::Status.create }
94
102
  end
95
-
103
+
96
104
  should "return an array of job ids" do
97
105
  assert Resque::Status.status_ids.is_a?(Array)
98
106
  assert_equal 32, Resque::Status.status_ids.size # 30 + 2
99
107
  end
100
-
108
+
101
109
  should "let you paginate through the statuses" do
102
110
  assert_equal Resque::Status.status_ids.reverse[0, 10], Resque::Status.status_ids(0, 10)
103
111
  assert_equal Resque::Status.status_ids.reverse[9, 10], Resque::Status.status_ids(10, 20)
104
112
  # assert_equal Resque::Status.status_ids.reverse[0, 10], Resque::Status.status_ids(0, 10)
105
113
  end
106
114
  end
107
-
115
+
108
116
  context ".statuses" do
109
-
117
+
110
118
  should "return an array status objects" do
111
119
  statuses = Resque::Status.statuses
112
120
  assert statuses.is_a?(Array)
113
121
  assert_same_elements [@uuid_with_json, @uuid], statuses.collect {|s| s.uuid }
114
122
  end
115
-
123
+
116
124
  end
117
-
125
+
118
126
  # context ".count" do
119
- #
127
+ #
120
128
  # should "return a count of statuses" do
121
129
  # statuses = Resque::Status.statuses
122
130
  # assert_equal 2, statuses.size
123
131
  # assert_equal statuses.size, Resque::Status.count
124
132
  # end
125
- #
133
+ #
126
134
  # end
127
-
135
+
128
136
  context ".logger" do
129
137
  setup do
130
138
  @logger = Resque::Status.logger(@uuid)
131
139
  end
132
-
140
+
133
141
  should "return a redisk logger" do
134
142
  assert @logger.is_a?(Redisk::Logger)
135
143
  end
136
-
144
+
137
145
  should "scope the logger to a key" do
138
146
  assert_match(/#{@uuid}/, @logger.name)
139
147
  end
140
-
148
+
141
149
  end
142
-
150
+
143
151
  end
144
152
 
145
153
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 2
8
- - 1
9
- version: 0.2.1
8
+ - 2
9
+ version: 0.2.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Aaron Quint
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-01-14 00:00:00 -08:00
17
+ date: 2011-02-09 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency