kthxbye 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.1
1
+ 1.0.2
data/config.ru CHANGED
@@ -4,4 +4,4 @@ $LOAD_PATH.unshift ::File.expand_path(::File.dirname(__FILE__) + '/lib')
4
4
  require 'kthxbye'
5
5
  require 'kthxbye/web_interface'
6
6
 
7
- Kthxbye::WebInterface.run! :host => "localhost", :port => 4567
7
+ Kthxbye::WebInterface.run! :host => ARGV[0], :port => ARGV[1]
@@ -18,15 +18,58 @@ require 'kthxbye/version'
18
18
 
19
19
  require 'kthxbye/exceptions'
20
20
 
21
+ # Kthxbye is a light-weight, distributed delayed-job processor. It is meant
22
+ # to take the load of long running processes off of your web-server any place
23
+ # it in the capable hands of a backend processor. It is unique in that it
24
+ # provides results delievery post-processing so that your front-end can actually
25
+ # have its results back.
26
+ #
27
+ # Most delayed job processors out there are meant for running processes that we
28
+ # don't need to get a result from. For example mass-mailings or image processing.
29
+ # However I've found many a case in which I need the result of a long process but
30
+ # my web server is bogging down watiting for a response.
31
+ #
32
+ # And this is where Kthxbye shines.
33
+ #
34
+ # Okay, you say, enough glowing, let's see this thinger work. Simple enough.
35
+ #
36
+ # On your front-end (e.g. a Rails app) initialization process, run
37
+ # Kthxbye::Config.setup(:redis_server => "localhost", :redis_port => 9876)
38
+ #
39
+ # Then somewhere accessable to both your app and your workers (maybe a separate
40
+ # job class file in you /lib dir) create your job class with a class method
41
+ # perform:
42
+ # class MyJob
43
+ # def self.perform(param1, param2)
44
+ # puts "I'm here with data!"
45
+ # # perform stuff with data
46
+ # result = param1 + param2
47
+ # return result
48
+ # end
49
+ # end
50
+ #
51
+ # Then all that's left is to queue up the job at the appropriate time:
52
+ # Kthxbye.enqueue("job-queue", MyJob, 6, 4)
53
+ #
54
+ # Your job is now queued for processing! To work this job, its even simpler.
55
+ # require 'whatever/file/my_job/class/is/in'
56
+ # worker = Kthxbye::Worker.new("job-queue")
57
+ # worker.run
58
+ #
59
+ # Let the processing commence!
21
60
  module Kthxbye
22
61
  include Helper
23
62
  extend self
24
63
 
25
- #takes in an existing redis instance or simply connects a new instance
64
+ # This is not necessary to call. Any of the methods that use redis
65
+ # Will make an inital call to connect to redis.
66
+ # Useful if you want to connect to an existing redis instance. Othewise, if
67
+ # called without params, it simply connects a new instance of redis.
26
68
  def connect( redis_instance=nil )
27
69
  @redis = ( redis_instance || Redis.new( :host => Config.options[:redis_server], :port => Config.options[:redis_port] ) )
28
70
  end
29
71
 
72
+ # Returns the Redis instance for direct calls to the Redis db
30
73
  def redis
31
74
  return @redis if @redis
32
75
  Config.setup
@@ -34,22 +77,32 @@ module Kthxbye
34
77
  self.redis
35
78
  end
36
79
 
80
+ # Returns a hash of all existing Redis keys.
37
81
  def keys
38
82
  redis.keys("*")
39
83
  end
40
84
 
41
- #
85
+ # Queues jobs. Takes at minimum two paramters
86
+ # 1) A string representing a queue
87
+ # 2) The class of the job being queued.
88
+ #
89
+ # You can optionally pass in additional params to the perform method within
90
+ # the class. You will need to match the number of args in the perform method
91
+ # when you queue the job. Otherwise this will throw an exception.
42
92
  def enqueue(queue, klass, *args)
43
93
  Job.create(queue, klass, *args)
44
94
  end
45
95
 
46
- # gets the size of a given queue
96
+ # Takes a string that represents a job queue.
97
+ # Returns the size of the given queue.
47
98
  def size(queue)
48
99
  redis.llen("queue:#{queue}").to_i
49
100
  end
50
101
 
51
- # gets the latest latest job off the given queue
52
- # returns a Job object
102
+ # This method is used mostly internally to pop the next job off of the given
103
+ # queue. It takes in a string representing a queue and will return a
104
+ # Kthxbye::Job object if a job exists on the queue. This is destructive on
105
+ # the queue as it will REMOVE the next job off queue and return the job object.
53
106
  def salvage(q)
54
107
  id = redis.lpop( "queue:#{q}" )
55
108
  if id
@@ -61,8 +114,12 @@ module Kthxbye
61
114
  end
62
115
  end
63
116
 
64
- # lets us peek at the data to be run with a job
65
- # can lookup an entire queue or for a specific job id
117
+ # This is a generic queue peek method. It isn't used directly but is the basis
118
+ # for the "ghost" methods "data_peek" and "result_peek". This method takes in
119
+ # a string representing a redis hash store (only two in kthxbye: "data-store"
120
+ # and "result-store"), a string representing a queue, and optionally a job id.
121
+ # If a job id is given, it will return the data for that job only. Otherwise
122
+ # it returns all the data for all jobs/results.
66
123
  def peek(store, queue, id=nil)
67
124
  if id
68
125
  decode( redis.hget( "#{store}-store:#{queue}", id ) )
@@ -74,8 +131,7 @@ module Kthxbye
74
131
  end
75
132
  end
76
133
 
77
- # handles a few of our dynamic methods
78
- def method_missing(name, *args)
134
+ def method_missing(name, *args) #:nodoc:
79
135
  method_name = name.id2name
80
136
  if method_name =~ /^(data|result)_peek$/
81
137
  Kthxbye.send(:peek, $1, *args)
@@ -85,36 +141,45 @@ module Kthxbye
85
141
 
86
142
  end
87
143
 
88
- # returns all the queues Kthxbye knows about
144
+ # Returns all the queues Kthxbye knows about
89
145
  def queues
90
146
  redis.smembers( :queues ).sort
91
147
  end
92
148
 
93
- # registers the queue in our "known queues" list
149
+ # This method takes a string and registers it as a queue in our "known queues"
150
+ # list
94
151
  def register_queue(queue)
95
152
  redis.sadd(:queues, queue) unless redis.sismember(:queues, queue)
96
153
  end
97
154
 
98
- # Removes the queue from the active queue listing, does not delete queue
99
- # will lead to phantom queues. use delete_queue for complete removal of queue
155
+ # Removes the queue from the active queue listing, does not delete queue.
156
+ # This will lead to phantom queues. use delete_queue for complete removal
157
+ # of queue.
100
158
  def unregister_queue(queue)
101
159
  redis.srem(:queues, queue)
102
160
  end
103
161
 
104
- # Completely removes queue: unregisters it then deletes it
105
- # should return true in all cases
162
+ # Completely removes queue: Unregisters it then deletes it should return true
163
+ # in all cases (including if we try to delete a non-existent queue).
106
164
  def delete_queue(queue)
107
165
  unregister_queue(queue)
108
166
  redis.del( "queue:#{queue}" ) || true
109
167
  end
110
168
 
111
- # returns all our registered workers
169
+ # Returns all workers registered with Kthxbye by the Kthxbye::Worker class.
170
+ # Special note: Workers are only registered once you call #run on the worker.
171
+ # You may also run #register_worker on the worker to manually register it, but
172
+ # this also occurs once the worker is run so there is no need to run this
173
+ # manually.
112
174
  def workers
113
175
  workers = redis.smembers( :workers )
114
176
  workers.map {|x| Worker.find( x ) }
115
177
  end
116
178
 
117
- # returns all our active workers and the job they are working
179
+ # Returns all of the workers that are currently working a job.
180
+ # Also returns the job id and started time of the worker as a hash as follows:
181
+ #
182
+ # [worker_id, {:job_id, :started}]
118
183
  def working
119
184
  workers = redis.smembers( :working )
120
185
  data = []
@@ -124,8 +189,9 @@ module Kthxbye
124
189
  return data
125
190
  end
126
191
 
127
- # returns either the job results for a specific job (if id specified)
128
- # or all the results for all the jobs on a queue
192
+ # Returns either the job results for a specific job (if id specified).
193
+ # If a job is not specified, it returns all the job results for the given
194
+ # queue.
129
195
  def job_results(queue, id=nil)
130
196
  if id
131
197
  decode( redis.hget( "result-store:#{queue}", id ) )
@@ -134,6 +200,7 @@ module Kthxbye
134
200
  end
135
201
  end
136
202
 
203
+ # Returns a pretty inspect message about this instance of Kthxbye.
137
204
  def inspect
138
205
  {
139
206
  :version => Version,
@@ -1,31 +1,32 @@
1
1
  module Kthxbye
2
+ # This module handles the setting and retrival of configuration options for
3
+ # Kthxbye.
2
4
  module Config
3
5
 
4
- # default options for Kthxbye
5
- #
6
- # redis_server = the ip to connect to by defaut
7
- #
8
- # redis_port = default redis port
9
- #
10
- # attempts = default number of attempts on a failing job
11
- # before moving to the failed job store
12
- #
13
- # vervose = more output
6
+ # Default options for Kthxbye
14
7
  #
8
+ # * redis_server = "127.0.0.1" - the ip to connect to by defaut
9
+ # * redis_port = 9876 - default redis port
10
+ # * attempts = 1 -default number of attempts on a failing job before a Failure
11
+ # is generated
12
+ # * vervose = false - more output in the worker log
15
13
  DEFAULT = {:redis_server => '127.0.0.1',
16
14
  :redis_port => 9876,
17
15
  :attempts => 1,
18
16
  :verbose => false}.freeze
19
17
 
20
- # configures any other args input by the user.
21
- # can pull from a config.yaml file as well.
22
- #
18
+ # This method takes override args input by the user.
19
+ # Can pull from a config/kthxbye.yaml file as well.
20
+ #
21
+ # NEEDS TO BE REWORKED FOR RAILS APPS
23
22
  def self.setup( args=nil )
24
23
  @options = DEFAULT.dup
25
- @options.merge!( YAML.load('config.yaml') ) if File.exist?( 'config.yaml' )
24
+ @options.merge!( YAML.load('./config/kthxbye.yaml') ) if File.exist?( './config/kthxbye.yaml' )
26
25
  @options.merge!( args ) if args
27
26
  end
28
27
 
28
+ # Quick access to the options hash. Works for setting individual options
29
+ # during runtime.
29
30
  def self.options
30
31
  return @options if @options
31
32
  Config.setup
@@ -1,4 +1,4 @@
1
1
  module Kthxbye
2
- # raised when a worker is killed during processing
2
+ # Raised when a worker is killed during processing
3
3
  class ActiveWorkerKilled < RuntimeError; end
4
4
  end
@@ -1,10 +1,8 @@
1
1
  module Kthxbye
2
- module Helper
3
-
2
+ module Helper #:nodoc: all
4
3
  def redis
5
4
  Kthxbye.redis
6
5
  end
7
-
8
6
  def log(msg)
9
7
  if Kthxbye::Config.options[:verbose]
10
8
  puts "!! #{msg} - #{Time.now.strftime("%I:%M%p")}"
@@ -1,4 +1,7 @@
1
1
  module Kthxbye
2
+
3
+ # This class is our main job runner. It also handles the instantiation and
4
+ # the meat of the job queuing and retreival.
2
5
  class Job
3
6
  include Helper
4
7
  extend Helper
@@ -6,11 +9,18 @@ module Kthxbye
6
9
  attr_accessor :id, :queue, :data, :worker
7
10
  attr_reader :failed_attempts
8
11
 
9
- def self.add_to_queue(queue, id)
12
+ # Adds a job to the queue from a given job id
13
+ # and queue. useful for switching a job to another queue or adding a defined
14
+ # job to multiple queues.
15
+ def self.add_to_queue(id, queue)
10
16
  redis.rpush( "queue:#{queue}", id )
11
17
  end
12
18
 
13
- # insert a job into the queue
19
+ # The bulk of the job queuing method. Takes a string representing a queue
20
+ # name, a job class, and arguments to pass to the perform method of the
21
+ # job class. Returns a unique id for the job based on a redis "uniq_id" key
22
+ # (int) which is a simple incremented value. Queues the job in the given
23
+ # queue and the job in the data-store hash.
14
24
  def self.create(queue, klass, *args)
15
25
  raise "Need a queue to store job in" if queue.to_s.empty?
16
26
  raise "No class to reference job type by" if klass.nil?
@@ -20,20 +30,23 @@ module Kthxbye
20
30
 
21
31
  Job.add_to_queue( queue, id )
22
32
  Kthxbye.register_queue( queue )
23
-
33
+
34
+ # mark job as inactive currently. will mark active when job is getting run
35
+ redis.redis.sadd("jobs:inactive", id)
24
36
  redis.hset( "data-store:#{queue}", id, encode( {:klass => klass, :payload => args} ) )
25
37
  log "Created job in queue #{queue} with an unique key of #{id}"
26
38
 
27
39
  return id.to_i
28
40
  end
29
41
 
42
+ # Returns a job object for a given job id off of a given queue.
30
43
  def self.find(id, queue)
31
44
  data = decode( redis.hget( "data-store:#{queue}", id ) )
32
45
  data ? Job.new(id, queue, data) : nil
33
46
  end
34
47
 
35
- # removes all existence of this job and its data
36
- # returns the last known status of the job
48
+ # Removes all existence of this job and its data
49
+ # Returns the last known status of the job
37
50
  def self.destroy(id, queue)
38
51
  ret = Job.find(id, queue).status
39
52
 
@@ -49,7 +62,9 @@ module Kthxbye
49
62
  return ret
50
63
  end
51
64
 
52
- # instantiates a job for the worker to run
65
+ # Instantiates a job from a job id, a queue, and the job data.
66
+ # Most often used in the ::find method and for the worker to recreate
67
+ # the job for running.
53
68
  def initialize(id, queue, data)
54
69
  @id = id.to_i
55
70
  @queue = queue
@@ -57,11 +72,16 @@ module Kthxbye
57
72
  @failed_attempts = Failure.fails_for_job(@id) # local tracking only, for rerun purposes
58
73
  end
59
74
 
60
- # simply requeues a job
75
+ # Simply requeues the job to be rerun.
61
76
  def rerun
62
77
  Job.add_to_queue( @queue, @id )
63
78
  end
64
79
 
80
+ # Returns the job's status. Will be one of 4 things.
81
+ # 1) :succeeded - the job ran and has a result
82
+ # 2) :failed - the job failed and reported an error
83
+ # 3) :active - job is being run.
84
+ # 4) :inactive - job is waiting to be run.
65
85
  def status
66
86
  if result
67
87
  :succeeded
@@ -74,28 +94,34 @@ module Kthxbye
74
94
  end
75
95
  end
76
96
 
97
+ # Returns the job's result once it has been run.
77
98
  def result
78
99
  decode( redis.hget("result-store:#{@queue}", @id) )
79
100
  end
80
101
 
81
- # simply removes this job from the active queue and places it
82
- # on the inactive list.
83
- # does not remove job payload
102
+ # Simply removes this job from the active queue and places it
103
+ # on the inactive list. Does not remove job payload from storage. It just
104
+ # removes its id from the actively run job queue.
84
105
  def dequeue
85
106
  redis.lrem("queue:#{@queue}", 0, @id)
86
107
  inactive
87
108
  end
88
109
 
89
- # does the heavy lifting of running a job
110
+ # Does all the heavy lifting of performing the job and storing the results.
111
+ # It will get the jobs class, payload and then run the job, storing the
112
+ # result in the result's store once complete. Also responsible for reporting
113
+ # errors and storing the job in the failure listing if an exception occurs.
90
114
  def perform
91
115
  begin
92
116
  @klass = Object.const_get(@data['klass'])
93
117
  @payload = @data['payload']
118
+ #set job active, getting ready to run
119
+ self.active
94
120
 
95
121
  result = @klass.send(:perform, *@payload)
96
122
  redis.hset( "result-store:#{@queue}", @id, encode( result ) )
97
123
  return result
98
- rescue Exception => ex
124
+ rescue Object => ex
99
125
  @failed_attempts += 1
100
126
  log "Error occured: #{ex.message}. Try: #{@failed_attempts}/#{Kthxbye::Config.options[:attempts]}"
101
127
  return Kthxbye::Failure.create( self, ex ) if @failed_attempts >= Kthxbye::Config.options[:attempts]
@@ -103,7 +129,7 @@ module Kthxbye
103
129
  end
104
130
  end
105
131
 
106
- # will allow us to track when this job is being worked
132
+ # Removes the job from the inactive queue.
107
133
  def active
108
134
  redis.srem("jobs:inactive", @id)
109
135
  end
@@ -112,11 +138,12 @@ module Kthxbye
112
138
  !redis.sismember("jobs:inactive", @id)
113
139
  end
114
140
 
141
+ # Places the job on the active queue
115
142
  def inactive
116
143
  redis.sadd("jobs:inactive", @id)
117
144
  end
118
145
 
119
- def ==(obj)
146
+ def ==(obj) #:nodoc:
120
147
  return false if obj.nil?
121
148
  @data == obj.data &&
122
149
  @id == obj.id &&
@@ -1,5 +1,5 @@
1
1
  module Kthxbye
2
- # may be a bad idea if only lib dir is installed...
2
+ # Returns current version of Kthxbye
3
3
  Version = VERSION = File.read(File.dirname(__FILE__)+'/../../VERSION').chomp
4
4
  end
5
5
 
@@ -3,7 +3,7 @@ require 'haml'
3
3
  require 'kthxbye'
4
4
 
5
5
  module Kthxbye
6
- class WebInterface < Sinatra::Base
6
+ class WebInterface < Sinatra::Base #:nodoc: all
7
7
  base = File.dirname( File.expand_path(__FILE__) )
8
8
 
9
9
  set :views, "#{base}/web_interface/views"
@@ -1,16 +1,24 @@
1
1
  module Kthxbye
2
+ # This is the workhorse loop of the gem. Does all the dequeuing and running of jobs.
3
+ # It mostly makes a bunch of calls to the job methods to run the job. It simply handles
4
+ # the spawning off of processes to run the job and retry if necessary.
2
5
  class Worker
3
6
  include Helper
4
7
  extend Helper
5
8
 
6
9
  attr_accessor :sleep_for, :queues, :current_queue, :id
7
10
 
11
+ # Creates a worker for running jobs off of a given queue.
12
+ # Takes a queue or queues (csv style, e.g. test,other,bad) or the woldcard
13
+ # (*) symbol to take in all queues in alphabetical order.
14
+ # Optionally takes in an interval param on how long it waits to check the
15
+ # queue for new jobs once it has exhausted the queue(s).
8
16
  def initialize(queues, sleep_for=5)
9
17
  setup_queues(queues)
10
18
  @sleep_for = sleep_for
11
19
  end
12
20
 
13
- def setup_queues(queues)
21
+ def setup_queues(queues) # :nodoc:
14
22
  if queues == "*"
15
23
  @queues = Kthxbye.queues.sort
16
24
  elsif queues.include? ?,
@@ -20,6 +28,8 @@ module Kthxbye
20
28
  end
21
29
  end
22
30
 
31
+ # Allows us to find a worker so that we can look at some of its internal data
32
+ # later on.
23
33
  def self.find(worker)
24
34
  if exists? worker
25
35
  qs = worker.split(':')[-1].split(",")
@@ -31,20 +41,21 @@ module Kthxbye
31
41
  end
32
42
  end
33
43
 
44
+ # Checks if a worker is registered.
34
45
  def self.exists?(id)
35
46
  redis.sismember( :workers, id )
36
47
  end
37
48
 
38
- # gets the job a given worker is working on
39
- # returns a hash with the 'job_id' and the 'started' time
49
+ # Gets the job a given worker is working on
50
+ # Returns a hash with the 'job_id' and the 'started' time
40
51
  def self.working_on(id)
41
52
  decode( redis.get( "worker:#{id}" ) )
42
53
  end
43
54
 
44
- # major run loop. workhorse of a worker... sort of.
45
- # in the end, this loop simply runs the jobs in separate
46
- # processes by forking out the process then waiting for it
47
- # to return. we only process one
55
+ # This is the major run loop. Workhorse of a worker... sort of.
56
+ # In the end, this loop simply runs the jobs in separate processes by forking
57
+ # out the process then waiting for it to return. we only process one.
58
+ # Can optionally take in a block to run after the job has run.
48
59
  def run(&block)
49
60
  log "Starting Kthxbye::Worker #{self}"
50
61
  startup
@@ -75,23 +86,24 @@ module Kthxbye
75
86
  unregister_worker
76
87
  end
77
88
 
89
+ # Returns the queues this worker is attached toin alphabetical order.
78
90
  def queues
79
91
  @queues.sort
80
92
  end
81
93
 
82
- # startup actions
83
- def startup
94
+ # Run startup actions
95
+ def startup #:nodoc:
84
96
  register_worker
85
97
  register_signals
86
98
  end
87
99
 
88
- # adds worker to the workers list
100
+ # Adds this worker to the worker registry
89
101
  def register_worker
90
102
  log "Registered worker #{self}"
91
103
  redis.sadd( :workers, self ) if !exists?
92
104
  end
93
105
 
94
- # removes the worker from our workers list
106
+ # Removes the worker from our worker registry
95
107
  def unregister_worker
96
108
  log "Unregistered worker #{self}"
97
109
  if working?
@@ -104,14 +116,15 @@ module Kthxbye
104
116
  redis.srem :workers, self
105
117
  end
106
118
 
119
+ # Gets the current job this worker is working.
107
120
  def current_job
108
121
  return @current_job if @current_job
109
122
  data = decode( redis.get("worker:#{self}") )
110
123
  @current_job = Job.find( data['job_id'], @current_queue )
111
124
  end
112
125
 
113
- # start working actions
114
- def working(job)
126
+ # Run when the job starts running
127
+ def working(job) #:nodoc:
115
128
  redis.sadd( :working, self )
116
129
 
117
130
  data = encode( {:job_id => job.id, :started => Time.now.to_s} )
@@ -122,13 +135,13 @@ module Kthxbye
122
135
  job.active
123
136
  end
124
137
 
125
- # must be in working list and have a current job
138
+ # Is this job working?
126
139
  def working?
127
140
  redis.sismember( :working, self )
128
141
  end
129
142
 
130
143
  # job complete actions
131
- def done
144
+ def done #:nodoc:
132
145
  redis.srem( :working, self )
133
146
  redis.del( "worker:#{self}" )
134
147
  log "Completed job #{@current_job}"
@@ -138,7 +151,7 @@ module Kthxbye
138
151
  #
139
152
  # thanks to http://github.com/defunkt/resque/blob/master/lib/resque/worker.rb for these signals
140
153
  #
141
- def register_signals
154
+ def register_signals #:nordoc:
142
155
  trap('TERM') { shutdown! }
143
156
  trap('INT') { shutdown! }
144
157
 
@@ -154,17 +167,19 @@ module Kthxbye
154
167
  log "Registered signals"
155
168
  end
156
169
 
157
- def shutdown
170
+ # Shuts down the worker gracefully (once process has completed
171
+ def shutdown #:nodoc:
158
172
  log "Shutting down worker #{self}"
159
173
  @terminate = true
160
174
  end
161
175
 
162
- def shutdown!
176
+ # Hard kills the worker by killing the process.
177
+ def shutdown! #:nodoc:
163
178
  kill_child
164
179
  shutdown
165
180
  end
166
181
 
167
- def kill_child
182
+ def kill_child #:nodoc:
168
183
  if @child
169
184
  log "Killing child at #{@child}"
170
185
  if system("ps -o pid,state -p #{@child}")
@@ -176,7 +191,8 @@ module Kthxbye
176
191
  end
177
192
  end
178
193
 
179
- def grab_job
194
+ # Reserves a job off the queue
195
+ def grab_job #:nodoc:
180
196
  job = nil
181
197
  @queues.each do |q|
182
198
  @current_queue = q
@@ -188,32 +204,38 @@ module Kthxbye
188
204
  return job || false
189
205
  end
190
206
 
191
- def exists?
207
+ # Checks if this worker is registered.
208
+ def exists? #:nodoc:
192
209
  redis.sismember( :workers, self )
193
210
  end
194
211
 
212
+ # Returns the hostname of the machine this worker is running on
195
213
  def hostname
196
214
  @hostname ||= `hostname`.chomp
197
215
  end
198
216
 
217
+ # Returns the process id of this worker.
199
218
  def pid
200
219
  Process.pid
201
220
  end
202
221
 
222
+ # Returns a useful id with the hostname:pid:queues listing
223
+ # Same return as to_s
203
224
  def id
204
225
  @id ||= "#{hostname}:#{pid}:#{queues.join(",")}"
205
226
  end
206
227
  alias_method :to_s, :id
207
228
 
229
+ # nice inspect for the worker with the same info as #id
208
230
  def inspect
209
231
  "#<Worker: #{@id}>"
210
232
  end
211
233
 
212
- def ==(other)
234
+ def ==(other) #:nodoc:
213
235
  to_s == other.to_s
214
236
  end
215
237
 
216
- def <=>(other)
238
+ def <=>(other) #:nodoc:
217
239
  to_s <=> other.to_s
218
240
  end
219
241
 
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kthxbye
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
5
4
  prerelease: false
6
5
  segments:
7
6
  - 1
8
7
  - 0
9
- - 1
10
- version: 1.0.1
8
+ - 2
9
+ version: 1.0.2
11
10
  platform: ruby
12
11
  authors:
13
12
  - Luke van der Hoeven
@@ -15,112 +14,105 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-09-23 00:00:00 -04:00
17
+ date: 2010-09-24 00:00:00 -04:00
19
18
  default_executable:
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
22
- prerelease: false
23
21
  name: redis
24
- version_requirements: &id001 !ruby/object:Gem::Requirement
22
+ requirement: &id001 !ruby/object:Gem::Requirement
25
23
  none: false
26
24
  requirements:
27
25
  - - ">="
28
26
  - !ruby/object:Gem::Version
29
- hash: 3
30
27
  segments:
31
28
  - 0
32
29
  version: "0"
33
- requirement: *id001
34
30
  type: :runtime
35
- - !ruby/object:Gem::Dependency
36
31
  prerelease: false
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
37
34
  name: yajl-ruby
38
- version_requirements: &id002 !ruby/object:Gem::Requirement
35
+ requirement: &id002 !ruby/object:Gem::Requirement
39
36
  none: false
40
37
  requirements:
41
38
  - - ">="
42
39
  - !ruby/object:Gem::Version
43
- hash: 3
44
40
  segments:
45
41
  - 0
46
42
  version: "0"
47
- requirement: *id002
48
43
  type: :runtime
49
- - !ruby/object:Gem::Dependency
50
44
  prerelease: false
45
+ version_requirements: *id002
46
+ - !ruby/object:Gem::Dependency
51
47
  name: sinatra
52
- version_requirements: &id003 !ruby/object:Gem::Requirement
48
+ requirement: &id003 !ruby/object:Gem::Requirement
53
49
  none: false
54
50
  requirements:
55
51
  - - ">="
56
52
  - !ruby/object:Gem::Version
57
- hash: 3
58
53
  segments:
59
54
  - 0
60
55
  version: "0"
61
- requirement: *id003
62
56
  type: :runtime
63
- - !ruby/object:Gem::Dependency
64
57
  prerelease: false
58
+ version_requirements: *id003
59
+ - !ruby/object:Gem::Dependency
65
60
  name: shoulda
66
- version_requirements: &id004 !ruby/object:Gem::Requirement
61
+ requirement: &id004 !ruby/object:Gem::Requirement
67
62
  none: false
68
63
  requirements:
69
64
  - - ">="
70
65
  - !ruby/object:Gem::Version
71
- hash: 3
72
66
  segments:
73
67
  - 0
74
68
  version: "0"
75
- requirement: *id004
76
69
  type: :development
77
- - !ruby/object:Gem::Dependency
78
70
  prerelease: false
71
+ version_requirements: *id004
72
+ - !ruby/object:Gem::Dependency
79
73
  name: bundler
80
- version_requirements: &id005 !ruby/object:Gem::Requirement
74
+ requirement: &id005 !ruby/object:Gem::Requirement
81
75
  none: false
82
76
  requirements:
83
77
  - - ~>
84
78
  - !ruby/object:Gem::Version
85
- hash: 23
86
79
  segments:
87
80
  - 1
88
81
  - 0
89
82
  - 0
90
83
  version: 1.0.0
91
- requirement: *id005
92
84
  type: :development
93
- - !ruby/object:Gem::Dependency
94
85
  prerelease: false
86
+ version_requirements: *id005
87
+ - !ruby/object:Gem::Dependency
95
88
  name: jeweler
96
- version_requirements: &id006 !ruby/object:Gem::Requirement
89
+ requirement: &id006 !ruby/object:Gem::Requirement
97
90
  none: false
98
91
  requirements:
99
92
  - - ~>
100
93
  - !ruby/object:Gem::Version
101
- hash: 270495430
102
94
  segments:
103
95
  - 1
104
96
  - 5
105
97
  - 0
106
98
  - pre3
107
99
  version: 1.5.0.pre3
108
- requirement: *id006
109
100
  type: :development
110
- - !ruby/object:Gem::Dependency
111
101
  prerelease: false
102
+ version_requirements: *id006
103
+ - !ruby/object:Gem::Dependency
112
104
  name: rcov
113
- version_requirements: &id007 !ruby/object:Gem::Requirement
105
+ requirement: &id007 !ruby/object:Gem::Requirement
114
106
  none: false
115
107
  requirements:
116
108
  - - ">="
117
109
  - !ruby/object:Gem::Version
118
- hash: 3
119
110
  segments:
120
111
  - 0
121
112
  version: "0"
122
- requirement: *id007
123
113
  type: :development
114
+ prerelease: false
115
+ version_requirements: *id007
124
116
  description: "Kthxbye is the answer to a fairly unique-yet-common problem: Background job processing when we care about the result."
125
117
  email: hungerandthirst@gmail.com
126
118
  executables: []
@@ -185,7 +177,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
185
177
  requirements:
186
178
  - - ">="
187
179
  - !ruby/object:Gem::Version
188
- hash: 3
180
+ hash: 387221811
189
181
  segments:
190
182
  - 0
191
183
  version: "0"
@@ -194,7 +186,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
194
186
  requirements:
195
187
  - - ">="
196
188
  - !ruby/object:Gem::Version
197
- hash: 3
198
189
  segments:
199
190
  - 0
200
191
  version: "0"