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 collapse

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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Hash

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.



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

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

.clear(range_start = nil, range_end = nil) ⇒ Object

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



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

def self.clear(range_start = nil, range_end = nil)
  status_ids(range_start, range_end).each do |id|
    redis.del(status_key(id))
    redis.zrem(set_key, id)
  end
end

.countObject



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

def self.count
  redis.zcard(set_key)
end

.create(*messages) ⇒ Object

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



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

def self.create(*messages)
  uuid = generate_uuid
  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

.expire_inObject

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



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

def self.expire_in
  @expire_in
end

.expire_in=(seconds) ⇒ Object

Set the expire_in time in seconds



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

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

.generate_uuidObject



138
139
140
# File 'lib/resque/plugins/status/hash.rb', line 138

def self.generate_uuid
  UUID.generate(:compact)
end

.get(uuid) ⇒ Object

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

.hash_accessor(name, options = {}) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/resque/plugins/status/hash.rb', line 142

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

.kill(uuid) ⇒ Object

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’.



92
93
94
# File 'lib/resque/plugins/status/hash.rb', line 92

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

.kill_idsObject

Return the UUIDs of the jobs on the kill list



102
103
104
# File 'lib/resque/plugins/status/hash.rb', line 102

def self.kill_ids
  redis.smembers(kill_key)
end

.kill_keyObject



130
131
132
# File 'lib/resque/plugins/status/hash.rb', line 130

def self.kill_key
  "_kill"
end

.killed(uuid) ⇒ Object

Remove the job at UUID from the kill list



97
98
99
# File 'lib/resque/plugins/status/hash.rb', line 97

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

.logger(uuid, options = {}) ⇒ Object

returns a Redisk::Logger scoped to the UUID. Any options passed are passed to the logger initialization.

Ensures that Redisk is logging to the same Redis connection as Resque.



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

def self.logger(uuid, options = {})
  Redisk.redis = redis
  Redisk::Logger.new(logger_key(uuid), options)
end

.logger_key(uuid) ⇒ Object



134
135
136
# File 'lib/resque/plugins/status/hash.rb', line 134

def self.logger_key(uuid)
  "_log:#{uuid}"
end

.set(uuid, *messages) ⇒ Object

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



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

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

.set_keyObject



126
127
128
# File 'lib/resque/plugins/status/hash.rb', line 126

def self.set_key
  "_statuses"
end

.should_kill?(uuid) ⇒ Boolean

Check whether a job with UUID is on the kill list

Returns:

  • (Boolean)


107
108
109
# File 'lib/resque/plugins/status/hash.rb', line 107

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

.status_ids(range_start = nil, range_end = nil) ⇒ Object

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



75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/resque/plugins/status/hash.rb', line 75

def self.status_ids(range_start = nil, range_end = nil)
  unless range_end && range_start
    # 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) || []
  else
    # 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)) || [])
  end
end

.status_key(uuid) ⇒ Object



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

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

.statuses(range_start = nil, range_end = nil) ⇒ Object

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)

Parameters:

  • range_start (Numeric) (defaults to: nil)

    The optional starting range

  • range_end (Numeric) (defaults to: nil)

    The optional ending range



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

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

#inspectObject



235
236
237
# File 'lib/resque/plugins/status/hash.rb', line 235

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

#jsonObject

Return a JSON representation of the current object.



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

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

#killable?Boolean

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

Returns:

  • (Boolean)


218
219
220
# File 'lib/resque/plugins/status/hash.rb', line 218

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

#pct_completeObject

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



194
195
196
197
198
199
200
201
202
# File 'lib/resque/plugins/status/hash.rb', line 194

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

#timeObject

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



206
207
208
# File 'lib/resque/plugins/status/hash.rb', line 206

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

#to_json(*args) ⇒ Object



223
224
225
# File 'lib/resque/plugins/status/hash.rb', line 223

def to_json(*args)
  json
end