stormtroopers 0.1.6 → 0.1.7
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/bin/stormtroopers +1 -1
- data/lib/stormtroopers/army.rb +25 -5
- data/lib/stormtroopers/manager.rb +23 -3
- data/lib/stormtroopers/trooper/delayed_job.rb +5 -1
- data/lib/stormtroopers/trooper.rb +20 -2
- data/lib/stormtroopers/version.rb +1 -1
- data/spec/stormtroopers/army_spec.rb +9 -10
- data/spec/stormtroopers/manager_spec.rb +2 -1
- data/spec/stormtroopers/trooper_spec.rb +6 -6
- metadata +38 -32
data/bin/stormtroopers
CHANGED
data/lib/stormtroopers/army.rb
CHANGED
@@ -27,17 +27,31 @@ module Stormtroopers
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def need_more_troops?
|
30
|
-
cleanup
|
30
|
+
cleanup!
|
31
31
|
threads.count < max_threads
|
32
32
|
end
|
33
33
|
|
34
|
+
def idle?
|
35
|
+
cleanup!
|
36
|
+
threads.count == 0
|
37
|
+
end
|
38
|
+
|
39
|
+
def running_troopers
|
40
|
+
cleanup!
|
41
|
+
threads.map{ |thread| thread[:trooper] }.compact
|
42
|
+
end
|
43
|
+
|
44
|
+
def running_troopers_status
|
45
|
+
running_troopers.map(&:status)
|
46
|
+
end
|
47
|
+
|
34
48
|
def run_trooper(trooper)
|
35
49
|
threads << Thread.new do
|
36
50
|
begin
|
37
|
-
trooper
|
51
|
+
Thread.current[:trooper] = trooper
|
52
|
+
trooper.start
|
38
53
|
rescue Exception => exception
|
39
|
-
logger.error("#{exception.message}:\n#{exception.backtrace.join("\n")}")
|
40
|
-
trooper.exception(exception)
|
54
|
+
logger.error("Unexpected thread death for trooper: #{trooper.status rescue "failed to retrieve trooper status"} : #{exception.message}:\n#{exception.backtrace.join("\n")}")
|
41
55
|
ensure
|
42
56
|
if defined?(::Mongoid)
|
43
57
|
::Mongoid::IdentityMap.clear
|
@@ -49,12 +63,18 @@ module Stormtroopers
|
|
49
63
|
end
|
50
64
|
end
|
51
65
|
|
66
|
+
def running_task_names
|
67
|
+
threads.each
|
68
|
+
end
|
69
|
+
|
52
70
|
def finish
|
53
71
|
logger.debug("#{name}: Finishing")
|
54
72
|
threads.each(&:join)
|
55
73
|
end
|
56
74
|
|
57
|
-
|
75
|
+
private
|
76
|
+
|
77
|
+
def cleanup!
|
58
78
|
threads.reject!{ |thread| !thread.alive? }
|
59
79
|
end
|
60
80
|
|
@@ -16,9 +16,14 @@ module Stormtroopers
|
|
16
16
|
|
17
17
|
Signal.trap("INT") do
|
18
18
|
logger.info "Stopping, waiting for running jobs to complete"
|
19
|
+
log_current_status
|
19
20
|
@managing = false
|
20
21
|
end
|
21
22
|
|
23
|
+
Signal.trap("USR2") do
|
24
|
+
log_current_status
|
25
|
+
end
|
26
|
+
|
22
27
|
logger.info "Starting"
|
23
28
|
|
24
29
|
if config[:speed] == "ludicrous"
|
@@ -40,6 +45,15 @@ module Stormtroopers
|
|
40
45
|
logger.info "Stopped, all running jobs completed"
|
41
46
|
end
|
42
47
|
|
48
|
+
def log_current_status
|
49
|
+
logger.info "Current status"
|
50
|
+
armies.each do |army|
|
51
|
+
army.running_troopers_status.each do |status|
|
52
|
+
logger.info "#{army.name}: #{status}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
43
57
|
def managing?
|
44
58
|
@managing || false
|
45
59
|
end
|
@@ -67,9 +81,15 @@ module Stormtroopers
|
|
67
81
|
end
|
68
82
|
|
69
83
|
def logger
|
70
|
-
|
71
|
-
|
72
|
-
|
84
|
+
unless @logger
|
85
|
+
log_directory = File.join(working_directory, "log")
|
86
|
+
Dir.mkdir(log_directory) unless File.directory?(log_directory)
|
87
|
+
@logger = Logger.new(File.join(working_directory, "log", "stormtroopers.log"), 'daily')
|
88
|
+
logger.formatter = proc do |severity, datetime, progname, msg|
|
89
|
+
"#{datetime.strftime("%Y-%m-%d %H:%M:%S")} #{severity}: #{msg}\n"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
@logger
|
73
93
|
end
|
74
94
|
|
75
95
|
private
|
@@ -6,6 +6,10 @@ module Stormtroopers
|
|
6
6
|
@job = job
|
7
7
|
end
|
8
8
|
|
9
|
+
def task_name
|
10
|
+
"#{@job.name} (#{job.id})"
|
11
|
+
end
|
12
|
+
|
9
13
|
def run
|
10
14
|
job.invoke_job
|
11
15
|
job.destroy
|
@@ -21,7 +25,7 @@ module Stormtroopers
|
|
21
25
|
job.unlock
|
22
26
|
job.save!
|
23
27
|
else
|
24
|
-
logger.error("PERMANENTLY removing #{job.name} because of #{job.attempts} consecutive failures.")
|
28
|
+
logger.error("PERMANENTLY removing #{job.name} (#{job.id}) because of #{job.attempts} consecutive failures.")
|
25
29
|
job.hook(:failure)
|
26
30
|
job.fail!
|
27
31
|
end
|
@@ -1,12 +1,21 @@
|
|
1
1
|
module Stormtroopers
|
2
2
|
class Trooper
|
3
|
-
attr_reader :task, :parameters
|
3
|
+
attr_reader :task, :parameters, :started_at
|
4
4
|
|
5
5
|
def initialize(parameters = {}, &block)
|
6
6
|
@parameters = parameters
|
7
7
|
@task = block
|
8
8
|
end
|
9
9
|
|
10
|
+
def name
|
11
|
+
# Override with a useful name here for logging purposes
|
12
|
+
@task.to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def status
|
16
|
+
"#{name} running since #{started_at.strftime("%Y-%m-%d %H:%M:%S")} (#{(Time.now - started_at).to_i} seconds)" if started_at
|
17
|
+
end
|
18
|
+
|
10
19
|
def before_run
|
11
20
|
# Empty hook for overriding
|
12
21
|
end
|
@@ -17,17 +26,26 @@ module Stormtroopers
|
|
17
26
|
|
18
27
|
def exception(exception)
|
19
28
|
# Hook for to override handling exceptions
|
29
|
+
logger.error "Error processing #{name}: #{exception.message}"
|
30
|
+
logger.debug "Stacktrace #{name}:\n#{exception.backtrace.join("\n")}"
|
20
31
|
raise exception
|
21
32
|
end
|
22
33
|
|
23
34
|
def run
|
24
|
-
before_run
|
25
35
|
task.call
|
36
|
+
end
|
37
|
+
|
38
|
+
def start
|
39
|
+
@started_at = Time.now
|
40
|
+
before_run
|
41
|
+
run
|
26
42
|
after_run
|
27
43
|
rescue => e
|
28
44
|
exception(e)
|
29
45
|
end
|
30
46
|
|
47
|
+
private
|
48
|
+
|
31
49
|
def logger
|
32
50
|
Manager.logger
|
33
51
|
end
|
@@ -37,14 +37,14 @@ describe Stormtroopers::Army do
|
|
37
37
|
live_thread_stub = stub(:alive? => true)
|
38
38
|
dead_thread_stub = stub(:alive? => false)
|
39
39
|
army.stub(:threads).and_return([live_thread_stub, dead_thread_stub])
|
40
|
-
army.cleanup
|
40
|
+
army.send(:cleanup!)
|
41
41
|
army.threads.should eq([live_thread_stub])
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
45
|
describe "#manage" do
|
46
46
|
it "cleans up" do
|
47
|
-
army.should_receive(:cleanup)
|
47
|
+
army.should_receive(:cleanup!)
|
48
48
|
army.manage
|
49
49
|
end
|
50
50
|
|
@@ -66,15 +66,14 @@ describe Stormtroopers::Army do
|
|
66
66
|
describe "#run_trooper" do
|
67
67
|
it "creates a new thread and runs the trooper in it" do
|
68
68
|
trooper = mock
|
69
|
-
trooper.should_receive(:
|
69
|
+
trooper.should_receive(:start)
|
70
70
|
Thread.should_receive(:new).and_yield
|
71
71
|
army.run_trooper(trooper)
|
72
72
|
end
|
73
73
|
|
74
74
|
it "calls trooper exception hook with the exception when trooper#run raises one" do
|
75
75
|
exception = StandardError.new
|
76
|
-
trooper =
|
77
|
-
trooper.stub(:run) { raise exception }
|
76
|
+
trooper = Stormtroopers::Trooper.new { raise exception }
|
78
77
|
trooper.should_receive(:exception).with(exception)
|
79
78
|
Thread.should_receive(:new).and_yield
|
80
79
|
army.run_trooper(trooper)
|
@@ -82,9 +81,9 @@ describe Stormtroopers::Army do
|
|
82
81
|
|
83
82
|
it "calls logs the exceptions at error level when trooper#run raises one" do
|
84
83
|
exception = StandardError.new
|
85
|
-
trooper =
|
86
|
-
|
87
|
-
army.logger.should_receive(:error)
|
84
|
+
trooper = Stormtroopers::Trooper.new { raise exception }
|
85
|
+
army.send(:logger).should_receive(:error)
|
86
|
+
army.send(:logger).should_receive(:error)
|
88
87
|
Thread.should_receive(:new).and_yield
|
89
88
|
army.run_trooper(trooper)
|
90
89
|
end
|
@@ -98,7 +97,7 @@ describe Stormtroopers::Army do
|
|
98
97
|
Mongoid.should_receive(:session).with(:default).and_return(mongoid_session)
|
99
98
|
mongoid_session.should_receive(:disconnect)
|
100
99
|
trooper = mock
|
101
|
-
trooper.should_receive(:
|
100
|
+
trooper.should_receive(:start)
|
102
101
|
Thread.should_receive(:new).and_yield
|
103
102
|
army.run_trooper(trooper)
|
104
103
|
end
|
@@ -119,7 +118,7 @@ describe Stormtroopers::Army do
|
|
119
118
|
it "takes the logger from Stormtroopers::Manager" do
|
120
119
|
logger = stub
|
121
120
|
Stormtroopers::Manager.stub(:logger).and_return(logger)
|
122
|
-
army.logger.should equal(logger)
|
121
|
+
army.send(:logger).should equal(logger)
|
123
122
|
end
|
124
123
|
end
|
125
124
|
|
@@ -5,6 +5,7 @@ describe Stormtroopers::Manager do
|
|
5
5
|
|
6
6
|
before(:each) {
|
7
7
|
stub_const("Stormtroopers::Army", Class.new)
|
8
|
+
Stormtroopers::Manager.stub(:instance).and_return(Stormtroopers::Manager.send(:new))
|
8
9
|
}
|
9
10
|
|
10
11
|
describe "#working_directory" do
|
@@ -26,7 +27,7 @@ describe Stormtroopers::Manager do
|
|
26
27
|
describe "#logger" do
|
27
28
|
it "creates a logger to log/stormtroopers.log" do
|
28
29
|
logger = stub.as_null_object
|
29
|
-
Logger.should_receive(:new).with(File.join(manager.working_directory, "log", "stormtroopers.log")).and_return(logger)
|
30
|
+
Logger.should_receive(:new).with(File.join(manager.working_directory, "log", "stormtroopers.log"), 'daily').and_return(logger)
|
30
31
|
manager.logger.should equal(logger)
|
31
32
|
end
|
32
33
|
end
|
@@ -21,36 +21,36 @@ describe Stormtroopers::Trooper do
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
describe "#
|
24
|
+
describe "#start" do
|
25
25
|
let(:task) { lambda { puts "This is a task" } }
|
26
26
|
let(:trooper) { Stormtroopers::Trooper.new({}, &task) }
|
27
27
|
|
28
28
|
it "calls the before_run hook" do
|
29
29
|
trooper.should_receive(:before_run)
|
30
|
-
trooper.
|
30
|
+
trooper.start
|
31
31
|
end
|
32
32
|
|
33
33
|
it "calls call on the task" do
|
34
34
|
task.should_receive(:call)
|
35
|
-
trooper.
|
35
|
+
trooper.start
|
36
36
|
end
|
37
37
|
|
38
38
|
it "calls the after_run hook" do
|
39
39
|
trooper.should_receive(:after_run)
|
40
|
-
trooper.
|
40
|
+
trooper.start
|
41
41
|
end
|
42
42
|
|
43
43
|
it "when the task raises an exception the exception hook is called" do
|
44
44
|
task.stub(:call) { raise "Oops" }
|
45
45
|
trooper.should_receive(:exception)
|
46
|
-
trooper.
|
46
|
+
trooper.start
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
50
|
describe "#logger" do
|
51
51
|
it "uses the Stormtroopers::Manager#logger" do
|
52
52
|
trooper = Stormtroopers::Trooper.new
|
53
|
-
trooper.logger.should equal(Stormtroopers::Manager.logger)
|
53
|
+
trooper.send(:logger).should equal(Stormtroopers::Manager.logger)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
metadata
CHANGED
@@ -1,65 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stormtroopers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.7
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Andre Meij
|
9
9
|
- Mark Kremer
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-12-04 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
17
|
-
|
18
|
-
none: false
|
17
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
18
|
requirements:
|
20
19
|
- - ! '>='
|
21
20
|
- !ruby/object:Gem::Version
|
22
21
|
version: 3.2.0
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
26
22
|
none: false
|
23
|
+
requirement: !ruby/object:Gem::Requirement
|
27
24
|
requirements:
|
28
25
|
- - ! '>='
|
29
26
|
- !ruby/object:Gem::Version
|
30
27
|
version: 3.2.0
|
28
|
+
none: false
|
29
|
+
prerelease: false
|
30
|
+
type: :runtime
|
31
31
|
- !ruby/object:Gem::Dependency
|
32
32
|
name: rspec
|
33
|
-
|
34
|
-
none: false
|
33
|
+
version_requirements: !ruby/object:Gem::Requirement
|
35
34
|
requirements:
|
36
35
|
- - ! '>='
|
37
36
|
- !ruby/object:Gem::Version
|
38
|
-
version:
|
39
|
-
|
40
|
-
prerelease: false
|
41
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
version: !binary |-
|
38
|
+
MA==
|
42
39
|
none: false
|
40
|
+
requirement: !ruby/object:Gem::Requirement
|
43
41
|
requirements:
|
44
42
|
- - ! '>='
|
45
43
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
44
|
+
version: !binary |-
|
45
|
+
MA==
|
46
|
+
none: false
|
47
|
+
prerelease: false
|
48
|
+
type: :development
|
47
49
|
- !ruby/object:Gem::Dependency
|
48
50
|
name: rake
|
49
|
-
|
50
|
-
none: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
52
|
requirements:
|
52
53
|
- - ! '>='
|
53
54
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
55
|
-
|
56
|
-
prerelease: false
|
57
|
-
version_requirements: !ruby/object:Gem::Requirement
|
55
|
+
version: !binary |-
|
56
|
+
MA==
|
58
57
|
none: false
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
60
|
- - ! '>='
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version:
|
62
|
+
version: !binary |-
|
63
|
+
MA==
|
64
|
+
none: false
|
65
|
+
prerelease: false
|
66
|
+
type: :development
|
63
67
|
description: ! 'Stormtroopers is a jruby execution environment for delayed jobs '
|
64
68
|
email:
|
65
69
|
- andre@socialreferral.com
|
@@ -100,32 +104,34 @@ files:
|
|
100
104
|
- vagrant-provision
|
101
105
|
homepage: http://github.com/socialreferral/stormtroopers
|
102
106
|
licenses: []
|
103
|
-
post_install_message:
|
107
|
+
post_install_message:
|
104
108
|
rdoc_options: []
|
105
109
|
require_paths:
|
106
110
|
- lib
|
107
111
|
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
-
none: false
|
109
112
|
requirements:
|
110
113
|
- - ! '>='
|
111
114
|
- !ruby/object:Gem::Version
|
112
|
-
version: '0'
|
113
115
|
segments:
|
114
116
|
- 0
|
115
|
-
|
116
|
-
|
117
|
+
version: !binary |-
|
118
|
+
MA==
|
119
|
+
hash: 2
|
117
120
|
none: false
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
122
|
requirements:
|
119
123
|
- - ! '>='
|
120
124
|
- !ruby/object:Gem::Version
|
121
|
-
version: '0'
|
122
125
|
segments:
|
123
126
|
- 0
|
124
|
-
|
127
|
+
version: !binary |-
|
128
|
+
MA==
|
129
|
+
hash: 2
|
130
|
+
none: false
|
125
131
|
requirements: []
|
126
|
-
rubyforge_project:
|
132
|
+
rubyforge_project:
|
127
133
|
rubygems_version: 1.8.24
|
128
|
-
signing_key:
|
134
|
+
signing_key:
|
129
135
|
specification_version: 3
|
130
136
|
summary: Execute delayed jobs in a threaded jruby environment
|
131
137
|
test_files:
|