job_boss 0.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.
- data/README.markdown +43 -0
- data/Rakefile +15 -0
- data/bin/job_boss +27 -0
- data/doc/ActiveRecord/Base.html +343 -0
- data/doc/ActiveRecord.html +185 -0
- data/doc/CreateJobs.html +256 -0
- data/doc/JobBoss/Boss.html +413 -0
- data/doc/JobBoss/Config.html +342 -0
- data/doc/JobBoss/Job.html +754 -0
- data/doc/JobBoss/Queuer.html +231 -0
- data/doc/JobBoss.html +480 -0
- data/doc/Mongrel/HttpServer.html +275 -0
- data/doc/Mongrel.html +185 -0
- data/doc/Passenger/Railz/RequestHandler.html +271 -0
- data/doc/Passenger/Railz.html +185 -0
- data/doc/Passenger.html +185 -0
- data/doc/PhusionPassenger/Rack/RequestHandler.html +271 -0
- data/doc/PhusionPassenger/Rack.html +185 -0
- data/doc/PhusionPassenger/Railz/RequestHandler.html +271 -0
- data/doc/PhusionPassenger/Railz.html +185 -0
- data/doc/PhusionPassenger.html +187 -0
- data/doc/Rakefile.html +115 -0
- data/doc/Spawn/SpawnId.html +276 -0
- data/doc/Spawn.html +742 -0
- data/doc/bin/job_boss.html +58 -0
- data/doc/created.rid +9 -0
- data/doc/index.html +126 -0
- data/doc/lib/job_boss/boss_rb.html +64 -0
- data/doc/lib/job_boss/capistrano_rb.html +60 -0
- data/doc/lib/job_boss/configuror_rb.html +54 -0
- data/doc/lib/job_boss/job_rb.html +56 -0
- data/doc/lib/job_boss/queuer_rb.html +56 -0
- data/doc/lib/migrate_rb.html +52 -0
- data/doc/rdoc.css +706 -0
- data/doc/vendor/spawn/CHANGELOG.html +275 -0
- data/doc/vendor/spawn/LICENSE.html +151 -0
- data/doc/vendor/spawn/init_rb.html +54 -0
- data/doc/vendor/spawn/lib/patches_rb.html +56 -0
- data/doc/vendor/spawn/lib/spawn_rb.html +52 -0
- data/job_boss.gemspec +26 -0
- data/lib/job_boss/boss.rb +153 -0
- data/lib/job_boss/capistrano.rb +8 -0
- data/lib/job_boss/configuror.rb +40 -0
- data/lib/job_boss/job.rb +155 -0
- data/lib/job_boss/queuer.rb +37 -0
- data/lib/migrate.rb +27 -0
- metadata +151 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
module JobBoss
|
2
|
+
class Boss
|
3
|
+
class << self
|
4
|
+
# Used to set Boss configuration
|
5
|
+
# Usage:
|
6
|
+
# Boss.config.sleep_interval = 2
|
7
|
+
def config
|
8
|
+
require 'job_boss/config'
|
9
|
+
@@config ||= Config.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# Used to queue jobs
|
13
|
+
# Usage:
|
14
|
+
# Boss.queue.math.is_prime?(42)
|
15
|
+
def queue
|
16
|
+
require 'job_boss/queuer'
|
17
|
+
@@queuer ||= Queuer.new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(options = {})
|
22
|
+
@@config.working_dir ||= options[:working_dir]
|
23
|
+
@@config.sleep_interval ||= options[:sleep_interval]
|
24
|
+
@@config.employee_limit ||= options[:employee_limit]
|
25
|
+
@@config.database_yaml_path ||= options[:database_yaml_path]
|
26
|
+
@@config.jobs_path ||= options[:jobs_path]
|
27
|
+
|
28
|
+
@running_jobs = []
|
29
|
+
end
|
30
|
+
|
31
|
+
# Start the boss
|
32
|
+
def start
|
33
|
+
require 'active_record'
|
34
|
+
require 'yaml'
|
35
|
+
|
36
|
+
establish_active_record_connection
|
37
|
+
|
38
|
+
require_job_classes
|
39
|
+
|
40
|
+
require 'job_boss/job'
|
41
|
+
|
42
|
+
migrate
|
43
|
+
|
44
|
+
Signal.trap("HUP") do
|
45
|
+
stop
|
46
|
+
end
|
47
|
+
|
48
|
+
at_exit do
|
49
|
+
stop if Process.pid == BOSS_PID
|
50
|
+
end
|
51
|
+
|
52
|
+
puts "Job Boss started"
|
53
|
+
|
54
|
+
while true
|
55
|
+
unless (children_count = available_employees) > 0 && Job.pending.count > 0
|
56
|
+
sleep(@@config.sleep_interval)
|
57
|
+
next
|
58
|
+
end
|
59
|
+
|
60
|
+
Job.pending_paths.each do |path|
|
61
|
+
job = Job.pending.find_by_path(path)
|
62
|
+
next if job.nil?
|
63
|
+
|
64
|
+
job.dispatch
|
65
|
+
@running_jobs << job
|
66
|
+
|
67
|
+
children_count -= 1
|
68
|
+
break unless children_count > 0
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def stop
|
75
|
+
puts "Stopping #{@running_jobs.size} running employees..."
|
76
|
+
|
77
|
+
shutdown_running_jobs
|
78
|
+
|
79
|
+
puts "Job Boss stopped"
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
# Cleans up @running_jobs variable, getting rid of jobs which have
|
84
|
+
# completed, which have been cancelled, or which went MIA
|
85
|
+
def cleanup_running_jobs
|
86
|
+
Job.uncached do
|
87
|
+
@running_jobs = Job.running.where('id in (?)', @running_jobs)
|
88
|
+
|
89
|
+
cancelled_jobs = @running_jobs.select(&:cancelled?)
|
90
|
+
cancelled_jobs.each {|job| kill_job(job) }
|
91
|
+
@running_jobs -= cancelled_jobs
|
92
|
+
|
93
|
+
# Clean out any jobs whos processes have stopped running for some reason
|
94
|
+
@running_jobs = @running_jobs.select do |job|
|
95
|
+
begin
|
96
|
+
Process.kill(0, job.employee_pid.to_i)
|
97
|
+
rescue Errno::ESRCH
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Total number of employees which can be run
|
105
|
+
def available_employees
|
106
|
+
cleanup_running_jobs
|
107
|
+
|
108
|
+
@@config.employee_limit - @running_jobs.size
|
109
|
+
end
|
110
|
+
|
111
|
+
def establish_active_record_connection
|
112
|
+
@@config.database_yaml_path = File.join(@@config.working_dir, @@config.database_yaml_path) unless @@config.database_yaml_path[0] == ?/
|
113
|
+
|
114
|
+
raise "Database YAML file missing (#{@@config.database_yaml_path})" unless File.exist?(@@config.database_yaml_path)
|
115
|
+
|
116
|
+
config = YAML.load(File.read(@@config.database_yaml_path))
|
117
|
+
|
118
|
+
ActiveRecord::Base.establish_connection(config[@@config.environment])
|
119
|
+
end
|
120
|
+
|
121
|
+
def require_job_classes
|
122
|
+
@@config.jobs_path = File.join(@@config.working_dir, @@config.jobs_path) unless @@config.jobs_path[0] == ?/
|
123
|
+
|
124
|
+
raise "Jobs path missing (#{@@config.jobs_path})" unless File.exist?(@@config.jobs_path)
|
125
|
+
|
126
|
+
Dir.glob(File.join(@@config.jobs_path, '*.rb')).each {|job_class| require job_class }
|
127
|
+
end
|
128
|
+
|
129
|
+
def migrate
|
130
|
+
unless Job.table_exists?
|
131
|
+
require 'migrate'
|
132
|
+
CreateJobs.up
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def kill_job(job)
|
137
|
+
begin
|
138
|
+
Process.kill("HUP", job.employee_pid.to_i)
|
139
|
+
rescue Errno::ESRCH
|
140
|
+
nil
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def shutdown_running_jobs
|
145
|
+
cleanup_running_jobs
|
146
|
+
|
147
|
+
@running_jobs.each do |job|
|
148
|
+
kill_job(job)
|
149
|
+
job.mark_for_redo
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# Capistrano task for job_boss.
|
2
|
+
#
|
3
|
+
# Just add "require 'job_boss/capistrano'" in your Capistrano deploy.rb, and
|
4
|
+
# job_boss will be activated after each new deployment.
|
5
|
+
|
6
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
7
|
+
after "deploy:update_code", "job_boss:restart"
|
8
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module JobBoss
|
2
|
+
class Config
|
3
|
+
attr_accessor :working_dir, :database_yaml_path, :jobs_path, :sleep_interval, :employee_limit, :environment
|
4
|
+
|
5
|
+
def parse_args(argv, options = {})
|
6
|
+
@working_dir = options[:working_dir] || Dir.pwd
|
7
|
+
@database_yaml_path = 'config/database.yml'
|
8
|
+
@jobs_path = 'app/jobs'
|
9
|
+
@sleep_interval = 0.5
|
10
|
+
@employee_limit = 4
|
11
|
+
@environment = 'development'
|
12
|
+
|
13
|
+
require 'optparse'
|
14
|
+
|
15
|
+
OptionParser.new do |opts|
|
16
|
+
opts.banner = "Usage: job_boss [start|stop|restart|status|watch] [-- <options>]"
|
17
|
+
|
18
|
+
opts.on("-d", "--database-yaml PATH", "Path for database YAML (defaults to ./config/database.yml)") do |path|
|
19
|
+
@database_yaml_path = path
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.on("-j", "--jobs-path PATH", "Path to folder with job classes (defaults to ./app/jobs)") do |path|
|
23
|
+
@database_yaml_path = path
|
24
|
+
end
|
25
|
+
|
26
|
+
opts.on("-e", "--environment ENV", "Rails environment to use in database YAML file (defaults to 'development')") do |env|
|
27
|
+
@environment = env
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on("-s", "--sleep-interval INTERVAL", Integer, "Number of seconds for the boss to sleep between checks of the queue (default 0.5)") do |interval|
|
31
|
+
@sleep_interval = interval
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on("-c", "--child-limit LIMIT", Integer, "Maximum number of employees (default 4)") do |limit|
|
35
|
+
@employee_limit = limit
|
36
|
+
end
|
37
|
+
end.parse!(argv)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/job_boss/job.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
|
2
|
+
module JobBoss
|
3
|
+
class Job < ActiveRecord::Base
|
4
|
+
default_scope order('created_at')
|
5
|
+
|
6
|
+
serialize :args
|
7
|
+
serialize :result
|
8
|
+
serialize :error_backtrace
|
9
|
+
|
10
|
+
scope :pending, where('started_at IS NULL')
|
11
|
+
scope :running, where('started_at IS NOT NULL AND completed_at IS NULL')
|
12
|
+
scope :completed, where('completed_at IS NOT NULL')
|
13
|
+
|
14
|
+
# Method used by the boss to dispatch an employee
|
15
|
+
def dispatch
|
16
|
+
mark_as_started
|
17
|
+
puts "Dispatching Job ##{self.id}"
|
18
|
+
|
19
|
+
pid = fork do
|
20
|
+
$0 = "job_boss - employee (job ##{self.id})"
|
21
|
+
Process.setpriority(Process::PRIO_PROCESS, 0, 19)
|
22
|
+
|
23
|
+
begin
|
24
|
+
mark_employee
|
25
|
+
|
26
|
+
Signal.trap("HUP") do
|
27
|
+
mark_for_redo
|
28
|
+
end
|
29
|
+
|
30
|
+
result = self.class.call_path(self.path, *self.args)
|
31
|
+
self.update_attribute(:result, result)
|
32
|
+
rescue Exception => exception
|
33
|
+
mark_exception(exception)
|
34
|
+
puts "Error running job ##{self.id}!"
|
35
|
+
ensure
|
36
|
+
until mark_as_completed
|
37
|
+
sleep(1)
|
38
|
+
end
|
39
|
+
|
40
|
+
puts "Job ##{self.id} completed, exiting..."
|
41
|
+
Kernel.exit
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
Process.detach(pid)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Clear out the job and put it back onto the queue for processing
|
49
|
+
def mark_for_redo
|
50
|
+
self.reload
|
51
|
+
self.started_at = nil
|
52
|
+
self.result = nil
|
53
|
+
self.completed_at = nil
|
54
|
+
self.status = nil
|
55
|
+
self.error_message = nil
|
56
|
+
self.error_backtrace = nil
|
57
|
+
self.employee_host = nil
|
58
|
+
self.employee_pid = nil
|
59
|
+
self.save
|
60
|
+
end
|
61
|
+
|
62
|
+
# Is the job complete?
|
63
|
+
def completed?
|
64
|
+
!!completed_at
|
65
|
+
end
|
66
|
+
|
67
|
+
# Mark the job as cancelled so that the boss won't run the job and so that
|
68
|
+
# the employee running the job gets stopped (if it's been dispatched)
|
69
|
+
def cancel
|
70
|
+
mark_as_cancelled
|
71
|
+
end
|
72
|
+
|
73
|
+
# Has the job been cancelled?
|
74
|
+
def cancelled?
|
75
|
+
!!cancelled_at
|
76
|
+
end
|
77
|
+
|
78
|
+
# Did the job succeed?
|
79
|
+
def succeeded?
|
80
|
+
completed_at && (status == 'success')
|
81
|
+
end
|
82
|
+
|
83
|
+
# How long did the job take?
|
84
|
+
def time_taken
|
85
|
+
completed_at - started_at if completed_at && started_at
|
86
|
+
end
|
87
|
+
|
88
|
+
class << self
|
89
|
+
def wait_for_jobs(jobs, sleep_interval = 0.5)
|
90
|
+
running_jobs = jobs.dup
|
91
|
+
|
92
|
+
until Job.running.find_all_by_id(running_jobs.collect(&:id)).empty?
|
93
|
+
sleep(sleep_interval)
|
94
|
+
end
|
95
|
+
|
96
|
+
true
|
97
|
+
end
|
98
|
+
|
99
|
+
def result_hash(jobs)
|
100
|
+
jobs.inject({}) do |hash, job|
|
101
|
+
hash.merge(job.args => job.result)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def mark_as_started
|
109
|
+
update_attributes(:started_at => Time.now)
|
110
|
+
end
|
111
|
+
|
112
|
+
def mark_as_cancelled
|
113
|
+
update_attributes(:cancelled_at => Time.now)
|
114
|
+
end
|
115
|
+
|
116
|
+
def mark_employee
|
117
|
+
require 'socket'
|
118
|
+
update_attributes(:employee_host => Socket.gethostname,
|
119
|
+
:employee_pid => Process.pid)
|
120
|
+
end
|
121
|
+
|
122
|
+
def mark_exception(exception)
|
123
|
+
update_attributes(:status => 'error', :error_message => exception.message, :error_backtrace => exception.backtrace)
|
124
|
+
end
|
125
|
+
|
126
|
+
def mark_as_completed
|
127
|
+
self.status ||= 'success'
|
128
|
+
self.completed_at = Time.now
|
129
|
+
self.save
|
130
|
+
end
|
131
|
+
|
132
|
+
class << self
|
133
|
+
def call_path(path, *args)
|
134
|
+
require 'active_support'
|
135
|
+
|
136
|
+
raise ArgumentError, "Invalid path (must have #)" unless path.match(/.#./)
|
137
|
+
controller, action = path.split('#')
|
138
|
+
|
139
|
+
controller_object = begin
|
140
|
+
Kernel.const_get("#{controller.classify}Jobs").new
|
141
|
+
rescue NameError
|
142
|
+
raise ArgumentError, "Invalid controller"
|
143
|
+
end
|
144
|
+
|
145
|
+
raise ArgumentError, "Invalid path action" unless controller_object.respond_to?(action)
|
146
|
+
|
147
|
+
controller_object.send(action, *args)
|
148
|
+
end
|
149
|
+
|
150
|
+
def pending_paths
|
151
|
+
self.pending.except(:order).select('DISTINCT path').collect(&:path)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module JobBoss
|
2
|
+
class Queuer
|
3
|
+
def method_missing(method_id, *args)
|
4
|
+
require 'active_support'
|
5
|
+
|
6
|
+
method_name = method_id.id2name
|
7
|
+
|
8
|
+
if @class && @controller
|
9
|
+
# In here, we've already figured out the class, so assume the method_missing call is to the method
|
10
|
+
|
11
|
+
if @class.respond_to?(method_name)
|
12
|
+
require 'job_boss/job'
|
13
|
+
path = "#{@controller}##{method_name}"
|
14
|
+
|
15
|
+
@class = nil
|
16
|
+
@controller = nil
|
17
|
+
|
18
|
+
Job.create(:path => path,
|
19
|
+
:args => args)
|
20
|
+
else
|
21
|
+
raise ArgumentError, "Invalid action"
|
22
|
+
end
|
23
|
+
else
|
24
|
+
# Check to see if there's a jobs class
|
25
|
+
begin
|
26
|
+
@class = Kernel.const_get("#{method_name.classify}Jobs").new
|
27
|
+
|
28
|
+
@controller = method_name
|
29
|
+
rescue NameError
|
30
|
+
raise ArgumentError, "Invalid controller"
|
31
|
+
end
|
32
|
+
|
33
|
+
self
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/migrate.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
class CreateJobs < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :jobs do |t|
|
4
|
+
t.string :path
|
5
|
+
t.text :args
|
6
|
+
t.text :result
|
7
|
+
t.datetime :started_at
|
8
|
+
t.datetime :cancelled_at
|
9
|
+
t.datetime :completed_at
|
10
|
+
t.string :status
|
11
|
+
t.string :error_message
|
12
|
+
t.text :error_backtrace
|
13
|
+
|
14
|
+
t.string :employee_host
|
15
|
+
t.string :employee_pid
|
16
|
+
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
|
20
|
+
add_index :jobs, :path
|
21
|
+
add_index :jobs, :status
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.down
|
25
|
+
drop_table :jobs
|
26
|
+
end
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: job_boss
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 2
|
8
|
+
version: "0.2"
|
9
|
+
platform: ruby
|
10
|
+
authors:
|
11
|
+
- Brian Underwood
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
|
16
|
+
date: 2010-11-26 00:00:00 -05:00
|
17
|
+
default_executable: job_boss
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: activerecord
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: activesupport
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 0
|
42
|
+
version: "0"
|
43
|
+
type: :runtime
|
44
|
+
version_requirements: *id002
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: daemons
|
47
|
+
prerelease: false
|
48
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
segments:
|
54
|
+
- 0
|
55
|
+
version: "0"
|
56
|
+
type: :runtime
|
57
|
+
version_requirements: *id003
|
58
|
+
description: job_boss allows you to queue jobs which are unqueued by a "Job Boss" daemon and handed off to workers to process
|
59
|
+
email:
|
60
|
+
- ml+job_boss@semi-sentient.com
|
61
|
+
executables:
|
62
|
+
- job_boss
|
63
|
+
extensions: []
|
64
|
+
|
65
|
+
extra_rdoc_files: []
|
66
|
+
|
67
|
+
files:
|
68
|
+
- README.markdown
|
69
|
+
- Rakefile
|
70
|
+
- bin/job_boss
|
71
|
+
- doc/ActiveRecord.html
|
72
|
+
- doc/ActiveRecord/Base.html
|
73
|
+
- doc/CreateJobs.html
|
74
|
+
- doc/JobBoss.html
|
75
|
+
- doc/JobBoss/Boss.html
|
76
|
+
- doc/JobBoss/Config.html
|
77
|
+
- doc/JobBoss/Job.html
|
78
|
+
- doc/JobBoss/Queuer.html
|
79
|
+
- doc/Mongrel.html
|
80
|
+
- doc/Mongrel/HttpServer.html
|
81
|
+
- doc/Passenger.html
|
82
|
+
- doc/Passenger/Railz.html
|
83
|
+
- doc/Passenger/Railz/RequestHandler.html
|
84
|
+
- doc/PhusionPassenger.html
|
85
|
+
- doc/PhusionPassenger/Rack.html
|
86
|
+
- doc/PhusionPassenger/Rack/RequestHandler.html
|
87
|
+
- doc/PhusionPassenger/Railz.html
|
88
|
+
- doc/PhusionPassenger/Railz/RequestHandler.html
|
89
|
+
- doc/Rakefile.html
|
90
|
+
- doc/Spawn.html
|
91
|
+
- doc/Spawn/SpawnId.html
|
92
|
+
- doc/bin/job_boss.html
|
93
|
+
- doc/created.rid
|
94
|
+
- doc/index.html
|
95
|
+
- doc/lib/job_boss/boss_rb.html
|
96
|
+
- doc/lib/job_boss/capistrano_rb.html
|
97
|
+
- doc/lib/job_boss/configuror_rb.html
|
98
|
+
- doc/lib/job_boss/job_rb.html
|
99
|
+
- doc/lib/job_boss/queuer_rb.html
|
100
|
+
- doc/lib/migrate_rb.html
|
101
|
+
- doc/rdoc.css
|
102
|
+
- doc/vendor/spawn/CHANGELOG.html
|
103
|
+
- doc/vendor/spawn/LICENSE.html
|
104
|
+
- doc/vendor/spawn/init_rb.html
|
105
|
+
- doc/vendor/spawn/lib/patches_rb.html
|
106
|
+
- doc/vendor/spawn/lib/spawn_rb.html
|
107
|
+
- job_boss.gemspec
|
108
|
+
- lib/job_boss/boss.rb
|
109
|
+
- lib/job_boss/capistrano.rb
|
110
|
+
- lib/job_boss/configuror.rb
|
111
|
+
- lib/job_boss/job.rb
|
112
|
+
- lib/job_boss/queuer.rb
|
113
|
+
- lib/migrate.rb
|
114
|
+
has_rdoc: true
|
115
|
+
homepage: http://github.com/cheerfulstoic/job_boss
|
116
|
+
licenses: []
|
117
|
+
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options: []
|
120
|
+
|
121
|
+
require_paths:
|
122
|
+
- lib
|
123
|
+
- vendor
|
124
|
+
- vendor/spawn/lib
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
126
|
+
none: false
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
segments:
|
131
|
+
- 0
|
132
|
+
version: "0"
|
133
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
segments:
|
139
|
+
- 1
|
140
|
+
- 3
|
141
|
+
- 6
|
142
|
+
version: 1.3.6
|
143
|
+
requirements: []
|
144
|
+
|
145
|
+
rubyforge_project:
|
146
|
+
rubygems_version: 1.3.7
|
147
|
+
signing_key:
|
148
|
+
specification_version: 3
|
149
|
+
summary: Asyncronous, parallel job processing
|
150
|
+
test_files: []
|
151
|
+
|