resque-status 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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