job_boss 0.2 → 0.4
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 +25 -2
- data/Rakefile +21 -8
- data/bin/job_boss +1 -0
- data/doc/ActiveSupport/TestCase.html +584 -0
- data/doc/{Passenger.html → ActiveSupport.html} +10 -30
- data/doc/CreateJobs.html +31 -16
- data/doc/{Mongrel.html → DaemonTest.html} +23 -39
- data/doc/JobBoss/Boss.html +466 -68
- data/doc/JobBoss/Config.html +77 -39
- data/doc/JobBoss/Job.html +375 -97
- data/doc/JobBoss/Queuer.html +35 -21
- data/doc/JobBoss.html +14 -311
- data/doc/{ActiveRecord.html → MathJobs.html} +66 -36
- data/doc/Rakefile.html +43 -9
- data/doc/SleepJobs.html +251 -0
- data/doc/{PhusionPassenger.html → StringJobs.html} +66 -38
- data/doc/bin/job_boss.html +1 -1
- data/doc/created.rid +14 -8
- data/doc/index.html +63 -7
- data/doc/lib/job_boss/boss_rb.html +5 -1
- data/doc/lib/job_boss/{configuror_rb.html → config_rb.html} +2 -2
- data/doc/lib/job_boss/job_rb.html +3 -1
- data/doc/lib/job_boss/queuer_rb.html +1 -1
- data/doc/lib/migrate_rb.html +1 -1
- data/doc/{vendor/spawn/lib/spawn_rb.html → test/app_root/app/jobs/math_jobs_rb.html} +7 -7
- data/doc/{vendor/spawn/lib/patches_rb.html → test/app_root/app/jobs/sleep_jobs_rb.html} +8 -12
- data/doc/test/app_root/app/jobs/string_jobs_rb.html +52 -0
- data/doc/test/test_helper_rb.html +62 -0
- data/doc/{vendor/spawn/init_rb.html → test/unit/daemon_test_rb.html} +3 -3
- data/doc/test/unit/job_test_rb.html +60 -0
- data/job_boss.gemspec +3 -2
- data/lib/job_boss/boss.rb +29 -7
- data/lib/job_boss/config.rb +49 -0
- data/lib/job_boss/job.rb +57 -13
- data/lib/migrate.rb +3 -1
- data/test/app_root/app/jobs/math_jobs.rb +5 -0
- data/test/app_root/app/jobs/sleep_jobs.rb +9 -0
- data/test/app_root/app/jobs/string_jobs.rb +5 -0
- data/test/app_root/config/database.yml +22 -0
- data/test/test_helper.rb +113 -0
- data/test/unit/daemon_test.rb +29 -0
- data/test/unit/job_test.rb +73 -0
- metadata +46 -27
- data/doc/ActiveRecord/Base.html +0 -343
- data/doc/Mongrel/HttpServer.html +0 -275
- data/doc/Passenger/Railz/RequestHandler.html +0 -271
- data/doc/Passenger/Railz.html +0 -185
- data/doc/PhusionPassenger/Rack/RequestHandler.html +0 -271
- data/doc/PhusionPassenger/Rack.html +0 -185
- data/doc/PhusionPassenger/Railz/RequestHandler.html +0 -271
- data/doc/PhusionPassenger/Railz.html +0 -185
- data/doc/Spawn/SpawnId.html +0 -276
- data/doc/Spawn.html +0 -742
- data/doc/vendor/spawn/CHANGELOG.html +0 -275
- data/doc/vendor/spawn/LICENSE.html +0 -151
- data/lib/job_boss/configuror.rb +0 -40
@@ -24,17 +24,21 @@
|
|
24
24
|
<div id="metadata">
|
25
25
|
<dl>
|
26
26
|
<dt class="modified-date">Last Modified</dt>
|
27
|
-
<dd class="modified-date">2010-11-
|
27
|
+
<dd class="modified-date">2010-11-28 17:49:41 -0500</dd>
|
28
28
|
|
29
29
|
|
30
30
|
<dt class="requires">Requires</dt>
|
31
31
|
<dd class="requires">
|
32
32
|
<ul>
|
33
33
|
|
34
|
+
<li>active_support</li>
|
35
|
+
|
34
36
|
<li>job_boss/config</li>
|
35
37
|
|
36
38
|
<li>job_boss/queuer</li>
|
37
39
|
|
40
|
+
<li>logger</li>
|
41
|
+
|
38
42
|
<li>active_record</li>
|
39
43
|
|
40
44
|
<li>yaml</li>
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<head>
|
7
7
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
|
8
8
|
|
9
|
-
<title>File:
|
9
|
+
<title>File: config.rb [RDoc Documentation]</title>
|
10
10
|
|
11
11
|
<link type="text/css" media="screen" href="../../rdoc.css" rel="stylesheet" />
|
12
12
|
|
@@ -24,7 +24,7 @@
|
|
24
24
|
<div id="metadata">
|
25
25
|
<dl>
|
26
26
|
<dt class="modified-date">Last Modified</dt>
|
27
|
-
<dd class="modified-date">2010-11-
|
27
|
+
<dd class="modified-date">2010-11-28 10:39:29 -0500</dd>
|
28
28
|
|
29
29
|
|
30
30
|
<dt class="requires">Requires</dt>
|
@@ -24,13 +24,15 @@
|
|
24
24
|
<div id="metadata">
|
25
25
|
<dl>
|
26
26
|
<dt class="modified-date">Last Modified</dt>
|
27
|
-
<dd class="modified-date">2010-11-
|
27
|
+
<dd class="modified-date">2010-11-28 17:56:05 -0500</dd>
|
28
28
|
|
29
29
|
|
30
30
|
<dt class="requires">Requires</dt>
|
31
31
|
<dd class="requires">
|
32
32
|
<ul>
|
33
33
|
|
34
|
+
<li>yaml</li>
|
35
|
+
|
34
36
|
<li>socket</li>
|
35
37
|
|
36
38
|
<li>active_support</li>
|
data/doc/lib/migrate_rb.html
CHANGED
@@ -6,17 +6,17 @@
|
|
6
6
|
<head>
|
7
7
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
|
8
8
|
|
9
|
-
<title>File:
|
9
|
+
<title>File: math_jobs.rb [RDoc Documentation]</title>
|
10
10
|
|
11
|
-
<link type="text/css" media="screen" href="
|
11
|
+
<link type="text/css" media="screen" href="../../../../rdoc.css" rel="stylesheet" />
|
12
12
|
|
13
|
-
<script src="
|
13
|
+
<script src="../../../../js/jquery.js" type="text/javascript"
|
14
14
|
charset="utf-8"></script>
|
15
|
-
<script src="
|
15
|
+
<script src="../../../../js/thickbox-compressed.js" type="text/javascript"
|
16
16
|
charset="utf-8"></script>
|
17
|
-
<script src="
|
17
|
+
<script src="../../../../js/quicksearch.js" type="text/javascript"
|
18
18
|
charset="utf-8"></script>
|
19
|
-
<script src="
|
19
|
+
<script src="../../../../js/darkfish.js" type="text/javascript"
|
20
20
|
charset="utf-8"></script>
|
21
21
|
</head>
|
22
22
|
|
@@ -24,7 +24,7 @@
|
|
24
24
|
<div id="metadata">
|
25
25
|
<dl>
|
26
26
|
<dt class="modified-date">Last Modified</dt>
|
27
|
-
<dd class="modified-date">2010-11-
|
27
|
+
<dd class="modified-date">2010-11-28 10:56:16 -0500</dd>
|
28
28
|
|
29
29
|
|
30
30
|
<dt class="requires">Requires</dt>
|
@@ -6,17 +6,17 @@
|
|
6
6
|
<head>
|
7
7
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
|
8
8
|
|
9
|
-
<title>File:
|
9
|
+
<title>File: sleep_jobs.rb [RDoc Documentation]</title>
|
10
10
|
|
11
|
-
<link type="text/css" media="screen" href="
|
11
|
+
<link type="text/css" media="screen" href="../../../../rdoc.css" rel="stylesheet" />
|
12
12
|
|
13
|
-
<script src="
|
13
|
+
<script src="../../../../js/jquery.js" type="text/javascript"
|
14
14
|
charset="utf-8"></script>
|
15
|
-
<script src="
|
15
|
+
<script src="../../../../js/thickbox-compressed.js" type="text/javascript"
|
16
16
|
charset="utf-8"></script>
|
17
|
-
<script src="
|
17
|
+
<script src="../../../../js/quicksearch.js" type="text/javascript"
|
18
18
|
charset="utf-8"></script>
|
19
|
-
<script src="
|
19
|
+
<script src="../../../../js/darkfish.js" type="text/javascript"
|
20
20
|
charset="utf-8"></script>
|
21
21
|
</head>
|
22
22
|
|
@@ -24,7 +24,7 @@
|
|
24
24
|
<div id="metadata">
|
25
25
|
<dl>
|
26
26
|
<dt class="modified-date">Last Modified</dt>
|
27
|
-
<dd class="modified-date">2010-11-
|
27
|
+
<dd class="modified-date">2010-11-28 17:28:24 -0500</dd>
|
28
28
|
|
29
29
|
|
30
30
|
<dt class="requires">Requires</dt>
|
@@ -43,11 +43,7 @@
|
|
43
43
|
|
44
44
|
<div class="description">
|
45
45
|
<h2>Description</h2>
|
46
|
-
|
47
|
-
see
|
48
|
-
activerecord/lib/active_record/connection_adaptors/abstract/connection_specification.rb
|
49
|
-
</p>
|
50
|
-
|
46
|
+
|
51
47
|
</div>
|
52
48
|
|
53
49
|
</div>
|
@@ -0,0 +1,52 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
|
5
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
6
|
+
<head>
|
7
|
+
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
|
8
|
+
|
9
|
+
<title>File: string_jobs.rb [RDoc Documentation]</title>
|
10
|
+
|
11
|
+
<link type="text/css" media="screen" href="../../../../rdoc.css" rel="stylesheet" />
|
12
|
+
|
13
|
+
<script src="../../../../js/jquery.js" type="text/javascript"
|
14
|
+
charset="utf-8"></script>
|
15
|
+
<script src="../../../../js/thickbox-compressed.js" type="text/javascript"
|
16
|
+
charset="utf-8"></script>
|
17
|
+
<script src="../../../../js/quicksearch.js" type="text/javascript"
|
18
|
+
charset="utf-8"></script>
|
19
|
+
<script src="../../../../js/darkfish.js" type="text/javascript"
|
20
|
+
charset="utf-8"></script>
|
21
|
+
</head>
|
22
|
+
|
23
|
+
<body class="file file-popup">
|
24
|
+
<div id="metadata">
|
25
|
+
<dl>
|
26
|
+
<dt class="modified-date">Last Modified</dt>
|
27
|
+
<dd class="modified-date">2010-11-28 14:49:29 -0500</dd>
|
28
|
+
|
29
|
+
|
30
|
+
<dt class="requires">Requires</dt>
|
31
|
+
<dd class="requires">
|
32
|
+
<ul>
|
33
|
+
|
34
|
+
</ul>
|
35
|
+
</dd>
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
</dl>
|
40
|
+
</div>
|
41
|
+
|
42
|
+
<div id="documentation">
|
43
|
+
|
44
|
+
<div class="description">
|
45
|
+
<h2>Description</h2>
|
46
|
+
|
47
|
+
</div>
|
48
|
+
|
49
|
+
</div>
|
50
|
+
</body>
|
51
|
+
</html>
|
52
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
|
5
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
6
|
+
<head>
|
7
|
+
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
|
8
|
+
|
9
|
+
<title>File: test_helper.rb [RDoc Documentation]</title>
|
10
|
+
|
11
|
+
<link type="text/css" media="screen" href="../rdoc.css" rel="stylesheet" />
|
12
|
+
|
13
|
+
<script src="../js/jquery.js" type="text/javascript"
|
14
|
+
charset="utf-8"></script>
|
15
|
+
<script src="../js/thickbox-compressed.js" type="text/javascript"
|
16
|
+
charset="utf-8"></script>
|
17
|
+
<script src="../js/quicksearch.js" type="text/javascript"
|
18
|
+
charset="utf-8"></script>
|
19
|
+
<script src="../js/darkfish.js" type="text/javascript"
|
20
|
+
charset="utf-8"></script>
|
21
|
+
</head>
|
22
|
+
|
23
|
+
<body class="file file-popup">
|
24
|
+
<div id="metadata">
|
25
|
+
<dl>
|
26
|
+
<dt class="modified-date">Last Modified</dt>
|
27
|
+
<dd class="modified-date">2010-11-28 17:50:45 -0500</dd>
|
28
|
+
|
29
|
+
|
30
|
+
<dt class="requires">Requires</dt>
|
31
|
+
<dd class="requires">
|
32
|
+
<ul>
|
33
|
+
|
34
|
+
<li>rubygems</li>
|
35
|
+
|
36
|
+
<li>test/unit</li>
|
37
|
+
|
38
|
+
<li>sqlite3</li>
|
39
|
+
|
40
|
+
<li>fileutils</li>
|
41
|
+
|
42
|
+
<li>active_support</li>
|
43
|
+
|
44
|
+
</ul>
|
45
|
+
</dd>
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
</dl>
|
50
|
+
</div>
|
51
|
+
|
52
|
+
<div id="documentation">
|
53
|
+
|
54
|
+
<div class="description">
|
55
|
+
<h2>Description</h2>
|
56
|
+
|
57
|
+
</div>
|
58
|
+
|
59
|
+
</div>
|
60
|
+
</body>
|
61
|
+
</html>
|
62
|
+
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<head>
|
7
7
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
|
8
8
|
|
9
|
-
<title>File:
|
9
|
+
<title>File: daemon_test.rb [RDoc Documentation]</title>
|
10
10
|
|
11
11
|
<link type="text/css" media="screen" href="../../rdoc.css" rel="stylesheet" />
|
12
12
|
|
@@ -24,14 +24,14 @@
|
|
24
24
|
<div id="metadata">
|
25
25
|
<dl>
|
26
26
|
<dt class="modified-date">Last Modified</dt>
|
27
|
-
<dd class="modified-date">2010-11-
|
27
|
+
<dd class="modified-date">2010-11-28 17:42:32 -0500</dd>
|
28
28
|
|
29
29
|
|
30
30
|
<dt class="requires">Requires</dt>
|
31
31
|
<dd class="requires">
|
32
32
|
<ul>
|
33
33
|
|
34
|
-
<li>
|
34
|
+
<li>test_helper</li>
|
35
35
|
|
36
36
|
</ul>
|
37
37
|
</dd>
|
@@ -0,0 +1,60 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
|
5
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
6
|
+
<head>
|
7
|
+
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
|
8
|
+
|
9
|
+
<title>File: job_test.rb [RDoc Documentation]</title>
|
10
|
+
|
11
|
+
<link type="text/css" media="screen" href="../../rdoc.css" rel="stylesheet" />
|
12
|
+
|
13
|
+
<script src="../../js/jquery.js" type="text/javascript"
|
14
|
+
charset="utf-8"></script>
|
15
|
+
<script src="../../js/thickbox-compressed.js" type="text/javascript"
|
16
|
+
charset="utf-8"></script>
|
17
|
+
<script src="../../js/quicksearch.js" type="text/javascript"
|
18
|
+
charset="utf-8"></script>
|
19
|
+
<script src="../../js/darkfish.js" type="text/javascript"
|
20
|
+
charset="utf-8"></script>
|
21
|
+
</head>
|
22
|
+
|
23
|
+
<body class="file file-popup">
|
24
|
+
<div id="metadata">
|
25
|
+
<dl>
|
26
|
+
<dt class="modified-date">Last Modified</dt>
|
27
|
+
<dd class="modified-date">2010-11-28 17:55:00 -0500</dd>
|
28
|
+
|
29
|
+
|
30
|
+
<dt class="requires">Requires</dt>
|
31
|
+
<dd class="requires">
|
32
|
+
<ul>
|
33
|
+
|
34
|
+
<li>test_helper</li>
|
35
|
+
|
36
|
+
<li>active_record</li>
|
37
|
+
|
38
|
+
<li>job_boss/boss</li>
|
39
|
+
|
40
|
+
<li>job_boss/job</li>
|
41
|
+
|
42
|
+
</ul>
|
43
|
+
</dd>
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
</dl>
|
48
|
+
</div>
|
49
|
+
|
50
|
+
<div id="documentation">
|
51
|
+
|
52
|
+
<div class="description">
|
53
|
+
<h2>Description</h2>
|
54
|
+
|
55
|
+
</div>
|
56
|
+
|
57
|
+
</div>
|
58
|
+
</body>
|
59
|
+
</html>
|
60
|
+
|
data/job_boss.gemspec
CHANGED
@@ -4,7 +4,7 @@ $:.unshift lib unless $:.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "job_boss"
|
7
|
-
s.version = '0.
|
7
|
+
s.version = '0.4'
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.authors = ["Brian Underwood"]
|
10
10
|
s.email = ["ml+job_boss@semi-sentient.com"]
|
@@ -16,7 +16,8 @@ Gem::Specification.new do |s|
|
|
16
16
|
|
17
17
|
s.add_dependency "activerecord"
|
18
18
|
s.add_dependency "activesupport"
|
19
|
-
s.add_dependency "daemons"
|
19
|
+
s.add_dependency "daemons-mikehale"
|
20
|
+
s.add_dependency "sqlite3-ruby" # For testing
|
20
21
|
|
21
22
|
s.files = `git ls-files`.split("\n")
|
22
23
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
data/lib/job_boss/boss.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
1
3
|
module JobBoss
|
2
4
|
class Boss
|
3
5
|
class << self
|
6
|
+
extend ActiveSupport::Memoizable
|
4
7
|
# Used to set Boss configuration
|
5
8
|
# Usage:
|
6
9
|
# Boss.config.sleep_interval = 2
|
@@ -16,10 +19,27 @@ module JobBoss
|
|
16
19
|
require 'job_boss/queuer'
|
17
20
|
@@queuer ||= Queuer.new
|
18
21
|
end
|
22
|
+
|
23
|
+
def logger
|
24
|
+
@@config.log_path = resolve_path(@@config.log_path)
|
25
|
+
|
26
|
+
require 'logger'
|
27
|
+
Logger.new(@@config.log_path)
|
28
|
+
end
|
29
|
+
memoize :logger
|
30
|
+
|
31
|
+
# If path starts with '/', leave alone. Otherwise, prepend application_root
|
32
|
+
def resolve_path(path)
|
33
|
+
if path == ?/ || path.match(/^#{@@config.application_root}/)
|
34
|
+
path
|
35
|
+
else
|
36
|
+
File.join(@@config.application_root, path)
|
37
|
+
end
|
38
|
+
end
|
19
39
|
end
|
20
40
|
|
21
41
|
def initialize(options = {})
|
22
|
-
@@config.
|
42
|
+
@@config.application_root ||= options[:working_dir]
|
23
43
|
@@config.sleep_interval ||= options[:sleep_interval]
|
24
44
|
@@config.employee_limit ||= options[:employee_limit]
|
25
45
|
@@config.database_yaml_path ||= options[:database_yaml_path]
|
@@ -49,7 +69,7 @@ module JobBoss
|
|
49
69
|
stop if Process.pid == BOSS_PID
|
50
70
|
end
|
51
71
|
|
52
|
-
|
72
|
+
Boss.logger.info "Job Boss started"
|
53
73
|
|
54
74
|
while true
|
55
75
|
unless (children_count = available_employees) > 0 && Job.pending.count > 0
|
@@ -57,6 +77,8 @@ module JobBoss
|
|
57
77
|
next
|
58
78
|
end
|
59
79
|
|
80
|
+
# Go through each pending path so that we don't get stuck just processing
|
81
|
+
# long running jobs which would leave quicker jobs to suffocate
|
60
82
|
Job.pending_paths.each do |path|
|
61
83
|
job = Job.pending.find_by_path(path)
|
62
84
|
next if job.nil?
|
@@ -72,11 +94,11 @@ module JobBoss
|
|
72
94
|
end
|
73
95
|
|
74
96
|
def stop
|
75
|
-
|
97
|
+
Boss.logger.info "Stopping #{@running_jobs.size} running employees..."
|
76
98
|
|
77
99
|
shutdown_running_jobs
|
78
100
|
|
79
|
-
|
101
|
+
Boss.logger.info "Job Boss stopped"
|
80
102
|
end
|
81
103
|
|
82
104
|
private
|
@@ -109,7 +131,7 @@ private
|
|
109
131
|
end
|
110
132
|
|
111
133
|
def establish_active_record_connection
|
112
|
-
@@config.database_yaml_path =
|
134
|
+
@@config.database_yaml_path = Boss.resolve_path(@@config.database_yaml_path)
|
113
135
|
|
114
136
|
raise "Database YAML file missing (#{@@config.database_yaml_path})" unless File.exist?(@@config.database_yaml_path)
|
115
137
|
|
@@ -119,7 +141,7 @@ private
|
|
119
141
|
end
|
120
142
|
|
121
143
|
def require_job_classes
|
122
|
-
@@config.jobs_path =
|
144
|
+
@@config.jobs_path = Boss.resolve_path(@@config.jobs_path)
|
123
145
|
|
124
146
|
raise "Jobs path missing (#{@@config.jobs_path})" unless File.exist?(@@config.jobs_path)
|
125
147
|
|
@@ -135,7 +157,7 @@ private
|
|
135
157
|
|
136
158
|
def kill_job(job)
|
137
159
|
begin
|
138
|
-
Process.kill("
|
160
|
+
Process.kill("TERM", job.employee_pid.to_i)
|
139
161
|
rescue Errno::ESRCH
|
140
162
|
nil
|
141
163
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module JobBoss
|
2
|
+
class Config
|
3
|
+
attr_accessor :application_root, :database_yaml_path, :log_path, :jobs_path, :sleep_interval, :employee_limit, :environment
|
4
|
+
|
5
|
+
def parse_args(argv, options = {})
|
6
|
+
@application_root = options[:working_dir] || Dir.pwd
|
7
|
+
@database_yaml_path = 'config/database.yml'
|
8
|
+
@log_path = 'log/job_boss.log'
|
9
|
+
@jobs_path = 'app/jobs'
|
10
|
+
@sleep_interval = 0.5
|
11
|
+
@employee_limit = 4
|
12
|
+
@environment = 'development'
|
13
|
+
|
14
|
+
require 'optparse'
|
15
|
+
|
16
|
+
OptionParser.new do |opts|
|
17
|
+
opts.banner = "Usage: job_boss [start|stop|restart|run|zap] [-- <options>]"
|
18
|
+
|
19
|
+
opts.on("-r", "--application-root PATH", "Path for the application root upon which other paths depend (defaults to .)") do |path|
|
20
|
+
@application_root = path
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on("-d", "--database-yaml PATH", "Path for database YAML (defaults to <application-root>/#{@database_yaml_path})") do |path|
|
24
|
+
@database_yaml_path = path
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("-l", "--log-path PATH", "Path for log file (defaults to <application-root>/#{@log_path})") do |path|
|
28
|
+
@log_path = path
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on("-j", "--jobs-path PATH", "Path to folder with job classes (defaults to <application-root>/#{@jobs_path})") do |path|
|
32
|
+
@jobs_path = path
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on("-e", "--environment ENV", "Environment to use in database YAML file (defaults to '#{@environment}')") do |env|
|
36
|
+
@environment = env
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on("-s", "--sleep-interval INTERVAL", Integer, "Number of seconds for the boss to sleep between checks of the queue (default #{@sleep_interval})") do |interval|
|
40
|
+
@sleep_interval = interval
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on("-c", "--employee-limit LIMIT", Integer, "Maximum number of employees (default 4)") do |limit|
|
44
|
+
@employee_limit = limit
|
45
|
+
end
|
46
|
+
end.parse!(argv)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/job_boss/job.rb
CHANGED
@@ -7,37 +7,34 @@ module JobBoss
|
|
7
7
|
serialize :result
|
8
8
|
serialize :error_backtrace
|
9
9
|
|
10
|
-
scope :pending, where('started_at IS NULL')
|
10
|
+
scope :pending, where('started_at IS NULL AND cancelled_at IS NULL')
|
11
11
|
scope :running, where('started_at IS NOT NULL AND completed_at IS NULL')
|
12
12
|
scope :completed, where('completed_at IS NOT NULL')
|
13
13
|
|
14
14
|
# Method used by the boss to dispatch an employee
|
15
15
|
def dispatch
|
16
16
|
mark_as_started
|
17
|
-
|
17
|
+
Boss.logger.info "Dispatching Job ##{self.id}"
|
18
18
|
|
19
19
|
pid = fork do
|
20
|
-
$0 = "job_boss
|
20
|
+
$0 = "[job_boss] employee (job ##{self.id})"
|
21
21
|
Process.setpriority(Process::PRIO_PROCESS, 0, 19)
|
22
22
|
|
23
23
|
begin
|
24
24
|
mark_employee
|
25
25
|
|
26
|
-
|
27
|
-
mark_for_redo
|
28
|
-
end
|
26
|
+
value = self.class.call_path(self.path, *self.args)
|
29
27
|
|
30
|
-
|
31
|
-
self.update_attribute(:result, result)
|
28
|
+
self.update_attribute(:result, value)
|
32
29
|
rescue Exception => exception
|
33
30
|
mark_exception(exception)
|
34
|
-
|
31
|
+
Boss.logger.error "Error running job ##{self.id}!"
|
35
32
|
ensure
|
36
33
|
until mark_as_completed
|
37
34
|
sleep(1)
|
38
35
|
end
|
39
36
|
|
40
|
-
|
37
|
+
Boss.logger.info "Job ##{self.id} completed, exiting..."
|
41
38
|
Kernel.exit
|
42
39
|
end
|
43
40
|
end
|
@@ -45,6 +42,22 @@ module JobBoss
|
|
45
42
|
Process.detach(pid)
|
46
43
|
end
|
47
44
|
|
45
|
+
# Store result as first and only value of an array so that the value always gets serialized
|
46
|
+
# Was having issues with the boolean value of false getting stored as the string "f"
|
47
|
+
def result=(value)
|
48
|
+
write_attribute(:result, [value])
|
49
|
+
end
|
50
|
+
|
51
|
+
def result
|
52
|
+
# If the result is being called for but the job hasn't been completed, reload
|
53
|
+
# to check to see if there was a result
|
54
|
+
self.reload if !completed? && read_attribute(:result).nil?
|
55
|
+
|
56
|
+
value = read_attribute(:result)
|
57
|
+
|
58
|
+
value.is_a?(Array) ? value.first : value
|
59
|
+
end
|
60
|
+
|
48
61
|
# Clear out the job and put it back onto the queue for processing
|
49
62
|
def mark_for_redo
|
50
63
|
self.reload
|
@@ -80,16 +93,40 @@ module JobBoss
|
|
80
93
|
completed_at && (status == 'success')
|
81
94
|
end
|
82
95
|
|
96
|
+
# Has the job been assigned to an employee?
|
97
|
+
def assigned?
|
98
|
+
# If the #assigned? method is being called for but the job hasn't been completed, reload
|
99
|
+
# to check to see if it has been assigned
|
100
|
+
self.reload if !completed? && employee_pid.nil?
|
101
|
+
|
102
|
+
employee_pid && employee_host
|
103
|
+
end
|
104
|
+
|
83
105
|
# How long did the job take?
|
84
106
|
def time_taken
|
85
107
|
completed_at - started_at if completed_at && started_at
|
86
108
|
end
|
87
109
|
|
110
|
+
# If the job raised an exception, this method will return the instance of that exception
|
111
|
+
# with the message and backtrace
|
112
|
+
def error
|
113
|
+
# If the error is being called for but the job hasn't been completed, reload
|
114
|
+
# to check to see if there was a error
|
115
|
+
self.reload if !completed? && error_message.nil?
|
116
|
+
|
117
|
+
if error_class && error_message && error_backtrace
|
118
|
+
error = Kernel.const_get(error_class).new(error_message)
|
119
|
+
error.set_backtrace(error_backtrace)
|
120
|
+
error
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
88
124
|
class << self
|
89
125
|
def wait_for_jobs(jobs, sleep_interval = 0.5)
|
90
|
-
|
126
|
+
jobs = [jobs] if jobs.is_a?(Job)
|
91
127
|
|
92
|
-
|
128
|
+
ids = jobs.collect(&:id)
|
129
|
+
until Job.completed.find_all_by_id(ids).count == jobs.size
|
93
130
|
sleep(sleep_interval)
|
94
131
|
end
|
95
132
|
|
@@ -97,6 +134,13 @@ module JobBoss
|
|
97
134
|
end
|
98
135
|
|
99
136
|
def result_hash(jobs)
|
137
|
+
jobs = [jobs] if jobs.is_a?(Job)
|
138
|
+
|
139
|
+
# the #result method automatically reloads the result here if needed but this will
|
140
|
+
# do it in one SQL call
|
141
|
+
jobs = Job.find(jobs.collect(&:id))
|
142
|
+
|
143
|
+
require 'yaml'
|
100
144
|
jobs.inject({}) do |hash, job|
|
101
145
|
hash.merge(job.args => job.result)
|
102
146
|
end
|
@@ -120,7 +164,7 @@ private
|
|
120
164
|
end
|
121
165
|
|
122
166
|
def mark_exception(exception)
|
123
|
-
update_attributes(:status => 'error', :error_message => exception.message, :error_backtrace => exception.backtrace)
|
167
|
+
update_attributes(:status => 'error', :error_class => exception.class.to_s, :error_message => exception.message, :error_backtrace => exception.backtrace)
|
124
168
|
end
|
125
169
|
|
126
170
|
def mark_as_completed
|