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 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: