Class: Resque::Plugins::Status::Hash

Inherits:
Hash
  • Object
show all
Extended by:
Helpers
Defined in:
lib/resque/plugins/status/hash.rb

Overview

Resque::Plugins::Status::Hash is a Hash object that has helper methods for dealing with the common status attributes. It also has a number of class methods for creating/updating/retrieving status objects from Redis

Constant Summary

STATUSES =
%w{queued working completed failed killed}.freeze

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Hash) initialize(*args)

Create a new Resque::Plugins::Status::Hash object. If multiple arguments are passed it is assumed the first argument is the UUID and the rest are status objects. All arguments are subsequentily merged in order. Strings are assumed to be messages.



209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/resque/plugins/status/hash.rb', line 209

def initialize(*args)
  super nil
  base_status = {
    'time' => Time.now.to_i,
    'status' => 'queued'
  }
  base_status['uuid'] = args.shift if args.length > 1
  status_hash = args.inject(base_status) do |final, m|
    m = {'message' => m} if m.is_a?(String)
    final.merge(m || {})
  end
  self.replace(status_hash)
end

Class Method Details

+ (Object) clear(range_start = nil, range_end = nil)

clear statuses from redis passing an optional range. See `statuses` for info about ranges



52
53
54
55
56
# File 'lib/resque/plugins/status/hash.rb', line 52

def self.clear(range_start = nil, range_end = nil)
  status_ids(range_start, range_end).each do |id|
    remove(id)
  end
end

+ (Object) clear_completed(range_start = nil, range_end = nil)



58
59
60
61
62
63
64
# File 'lib/resque/plugins/status/hash.rb', line 58

def self.clear_completed(range_start = nil, range_end = nil)
  status_ids(range_start, range_end).select do |id|
    get(id).completed?
  end.each do |id|
    remove(id)
  end
end

+ (Object) clear_failed(range_start = nil, range_end = nil)



66
67
68
69
70
71
72
# File 'lib/resque/plugins/status/hash.rb', line 66

def self.clear_failed(range_start = nil, range_end = nil)
  status_ids(range_start, range_end).select do |id|
    get(id).failed?
  end.each do |id|
    remove(id)
  end
end

+ (Object) count



79
80
81
# File 'lib/resque/plugins/status/hash.rb', line 79

def self.count
  redis.zcard(set_key)
end

+ (Object) create(uuid, *messages)

Create a status, generating a new UUID, passing the message to the status Returns the UUID of the new status.



16
17
18
19
20
21
# File 'lib/resque/plugins/status/hash.rb', line 16

def self.create(uuid, *messages)
  set(uuid, *messages)
  redis.zadd(set_key, Time.now.to_i, uuid)
  redis.zremrangebyscore(set_key, 0, Time.now.to_i - @expire_in) if @expire_in
  uuid
end

+ (Object) expire_in

The time in seconds that jobs and statuses should expire from Redis (after the last time they are touched/updated)



148
149
150
# File 'lib/resque/plugins/status/hash.rb', line 148

def self.expire_in
  @expire_in
end

+ (Object) expire_in=(seconds)

Set the expire_in time in seconds



153
154
155
# File 'lib/resque/plugins/status/hash.rb', line 153

def self.expire_in=(seconds)
  @expire_in = seconds.nil? ? nil : seconds.to_i
end

+ (Object) generate_uuid



169
170
171
# File 'lib/resque/plugins/status/hash.rb', line 169

def self.generate_uuid
  SecureRandom.hex.to_s
end

+ (Object) get(uuid)

Get a status by UUID. Returns a Resque::Plugins::Status::Hash



24
25
26
27
# File 'lib/resque/plugins/status/hash.rb', line 24

def self.get(uuid)
  val = redis.get(status_key(uuid))
  val ? Resque::Plugins::Status::Hash.new(uuid, decode(val)) : nil
end

+ (Object) hash_accessor(name, options = {})



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/resque/plugins/status/hash.rb', line 173

def self.hash_accessor(name, options = {})
  options[:default] ||= nil
  coerce = options[:coerce] ? ".#{options[:coerce]}" : ""
  module_eval <<-EOT
  def #{name}
    value = (self['#{name}'] ? self['#{name}']#{coerce} : #{options[:default].inspect})
    yield value if block_given?
    value
  end

  def #{name}=(value)
    self['#{name}'] = value
  end

  def #{name}?
    !!self['#{name}']
  end
  EOT
end

+ (Object) kill(uuid)

Kill the job at UUID on its next iteration this works by adding the UUID to a kill list (a.k.a. a list of jobs to be killed. Each iteration the job checks if it should be killed by calling tick or at. If so, it raises a Resque::Plugins::Status::Killed error and sets the status to 'killed'.



113
114
115
# File 'lib/resque/plugins/status/hash.rb', line 113

def self.kill(uuid)
  redis.sadd(kill_key, uuid)
end

+ (Object) kill_ids

Return the UUIDs of the jobs on the kill list



123
124
125
# File 'lib/resque/plugins/status/hash.rb', line 123

def self.kill_ids
  redis.smembers(kill_key)
end

+ (Object) kill_key



165
166
167
# File 'lib/resque/plugins/status/hash.rb', line 165

def self.kill_key
  "_kill"
end

+ (Object) killall(range_start = nil, range_end = nil)

Kills num jobs within range starting with the most recent first. By default kills all jobs. Note that the same conditions apply as kill, i.e. only jobs that check on each iteration by calling tick or at are eligible to killed.

Examples:

killing the last 20 submitted jobs

Resque::Plugins::Status::Hash.killall(0, 20)


135
136
137
138
139
# File 'lib/resque/plugins/status/hash.rb', line 135

def self.killall(range_start = nil, range_end = nil)
  status_ids(range_start, range_end).collect do |id|
    kill(id)
  end
end

+ (Object) killed(uuid)

Remove the job at UUID from the kill list



118
119
120
# File 'lib/resque/plugins/status/hash.rb', line 118

def self.killed(uuid)
  redis.srem(kill_key, uuid)
end

+ (Object) mget(uuids)

Get multiple statuses by UUID. Returns array of Resque::Plugins::Status::Hash



30
31
32
33
34
35
36
37
# File 'lib/resque/plugins/status/hash.rb', line 30

def self.mget(uuids)
  status_keys = uuids.map{|u| status_key(u)}
  vals = redis.mget(*status_keys)

  uuids.zip(vals).map do |uuid, val|
    val ? Resque::Plugins::Status::Hash.new(uuid, decode(val)) : nil
  end
end

+ (Object) remove(uuid)



74
75
76
77
# File 'lib/resque/plugins/status/hash.rb', line 74

def self.remove(uuid)
  redis.del(status_key(uuid))
  redis.zrem(set_key, uuid)
end

+ (Object) set(uuid, *messages)

set a status by UUID. messages can be any number of strings or hashes that are merged in order to create a single status.



41
42
43
44
45
46
47
48
# File 'lib/resque/plugins/status/hash.rb', line 41

def self.set(uuid, *messages)
  val = Resque::Plugins::Status::Hash.new(uuid, *messages)
  redis.set(status_key(uuid), encode(val))
  if expire_in
    redis.expire(status_key(uuid), expire_in)
  end
  val
end

+ (Object) set_key



161
162
163
# File 'lib/resque/plugins/status/hash.rb', line 161

def self.set_key
  "_statuses"
end

+ (Boolean) should_kill?(uuid)

Check whether a job with UUID is on the kill list



142
143
144
# File 'lib/resque/plugins/status/hash.rb', line 142

def self.should_kill?(uuid)
  redis.sismember(kill_key, uuid)
end

+ (Object) status_ids(range_start = nil, range_end = nil)

Return the num most recent status/job UUIDs in reverse chronological order.



96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/resque/plugins/status/hash.rb', line 96

def self.status_ids(range_start = nil, range_end = nil)
  if range_end && range_start
    # Because we want a reverse chronological order, we need to get a range starting
    # by the higest negative number. The ordering is transparent from the API user's
    # perspective so we need to convert the passed params
    (redis.zrevrange(set_key, (range_start.abs), ((range_end || 1).abs)) || [])
  else
    # Because we want a reverse chronological order, we need to get a range starting
    # by the higest negative number.
    redis.zrevrange(set_key, 0, -1) || []
  end
end

+ (Object) status_key(uuid)



157
158
159
# File 'lib/resque/plugins/status/hash.rb', line 157

def self.status_key(uuid)
  "status:#{uuid}"
end

+ (Object) statuses(range_start = nil, range_end = nil)

Return num Resque::Plugins::Status::Hash objects in reverse chronological order. By default returns the entire set.

Examples:

retuning the last 20 statuses

Resque::Plugins::Status::Hash.statuses(0, 20)


89
90
91
92
93
# File 'lib/resque/plugins/status/hash.rb', line 89

def self.statuses(range_start = nil, range_end = nil)
  status_ids(range_start, range_end).collect do |id|
    get(id)
  end.compact
end

Instance Method Details

- (Object) inspect



266
267
268
# File 'lib/resque/plugins/status/hash.rb', line 266

def inspect
  "#<Resque::Plugins::Status::Hash #{super}>"
end

- (Object) json

Return a JSON representation of the current object.



260
261
262
263
264
# File 'lib/resque/plugins/status/hash.rb', line 260

def json
  h = self.dup
  h['pct_complete'] = pct_complete
  self.class.encode(h)
end

- (Boolean) killable?

Can the job be killed? 'failed', 'completed', and 'killed' jobs cant be killed (for pretty obvious reasons)



249
250
251
# File 'lib/resque/plugins/status/hash.rb', line 249

def killable?
  !['failed', 'completed', 'killed'].include?(self.status)
end

- (Object) pct_complete

calculate the % completion of the job based on status, num and total



225
226
227
228
229
230
231
232
233
# File 'lib/resque/plugins/status/hash.rb', line 225

def pct_complete
  case status
  when 'completed' then 100
  when 'queued' then 0
  else
    t = (total == 0 || total.nil?) ? 1 : total
    (((num || 0).to_f / t.to_f) * 100).to_i
  end
end

- (Object) time

Return the time of the status initialization. If set returns a Time object, otherwise returns nil



237
238
239
# File 'lib/resque/plugins/status/hash.rb', line 237

def time
  time? ? Time.at(self['time']) : nil
end

- (Object) to_json(*args)



254
255
256
# File 'lib/resque/plugins/status/hash.rb', line 254

def to_json(*args)
  json
end