stormtroopers 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
data/bin/stormtroopers CHANGED
@@ -3,7 +3,7 @@
3
3
  begin
4
4
  require "config/environment"
5
5
  rescue LoadError
6
- puts "Could not load environment"
6
+ puts "Could not load rails environment, running standalone"
7
7
  end
8
8
 
9
9
  require_relative "../lib/stormtroopers"
@@ -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.run
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
- def cleanup
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
- log_directory = File.join(working_directory, "log")
71
- Dir.mkdir(log_directory) unless File.directory?(log_directory)
72
- @logger ||= Logger.new(File.join(working_directory, "log", "stormtroopers.log"))
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
@@ -1,3 +1,3 @@
1
1
  module Stormtroopers
2
- VERSION = "0.1.6"
2
+ VERSION = "0.1.7"
3
3
  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(:run)
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 = stub
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 = stub.as_null_object
86
- trooper.stub(:run) { raise exception }
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(:run)
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 "#run" do
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.run
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.run
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.run
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.run
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.6
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-11-26 00:00:00.000000000 Z
13
+ date: 2012-12-04 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
17
- requirement: !ruby/object:Gem::Requirement
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
- requirement: !ruby/object:Gem::Requirement
34
- none: false
33
+ version_requirements: !ruby/object:Gem::Requirement
35
34
  requirements:
36
35
  - - ! '>='
37
36
  - !ruby/object:Gem::Version
38
- version: '0'
39
- type: :development
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: '0'
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
- requirement: !ruby/object:Gem::Requirement
50
- none: false
51
+ version_requirements: !ruby/object:Gem::Requirement
51
52
  requirements:
52
53
  - - ! '>='
53
54
  - !ruby/object:Gem::Version
54
- version: '0'
55
- type: :development
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: '0'
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
- hash: -456344668358757306
116
- required_rubygems_version: !ruby/object:Gem::Requirement
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
- hash: -456344668358757306
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: