job_boss 0.5.8 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -84,6 +84,12 @@ job_boss also makes it easy to wait for the jobs to be done and to collect the r
84
84
 
85
85
  Job.result_hash(jobs) # => {[0]=>false, [1]=>false, [2]=>true, [3]=>true, [4]=>false, ... }
86
86
 
87
+ You can even define a block to provide updates on progress (the value which is passed into the block is a float between 0.0 and 100.0):
88
+
89
+ Job.wait_for_jobs(jobs) do |progress|
90
+ puts "We're now at #{progress}%"
91
+ end
92
+
87
93
  For performance, it is recommended that you keep your jobs table clean scheduling execution of the `delete_jobs_before` command on the Job model, which will clean all jobs completed before the specified time:
88
94
 
89
95
  Job.delete_jobs_before(2.days.ago)
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.5.8'
7
+ s.version = '0.6.0'
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Brian Underwood"]
10
10
  s.email = ["ml+job_boss@semi-sentient.com"]
data/lib/job_boss/boss.rb CHANGED
@@ -124,7 +124,10 @@ private
124
124
  @running_jobs = Job.running.where('id in (?)', @running_jobs)
125
125
 
126
126
  cancelled_jobs = @running_jobs.select(&:cancelled?)
127
- cancelled_jobs.each {|job| kill_job(job) }
127
+ cancelled_jobs.each do |job|
128
+ logger.warn "Cancelling job ##{job.id}"
129
+ kill_job(job)
130
+ end
128
131
  @running_jobs -= cancelled_jobs
129
132
 
130
133
  # Clean out any jobs whos processes have stopped running for some reason
@@ -132,6 +135,8 @@ private
132
135
  begin
133
136
  Process.kill(0, job.employee_pid.to_i)
134
137
  rescue Errno::ESRCH
138
+ logger.warn "Job ##{job.id} MIA!"
139
+ job.mark_as_mia
135
140
  nil
136
141
  end
137
142
  end
@@ -174,6 +179,7 @@ private
174
179
  begin
175
180
  Process.kill("TERM", job.employee_pid.to_i)
176
181
  rescue Errno::ESRCH
182
+ logger.error "Could not kill job ##{job.id}!"
177
183
  nil
178
184
  end
179
185
  end
data/lib/job_boss/job.rb CHANGED
@@ -10,15 +10,20 @@ module JobBoss
10
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
+ scope :mia, where("completed_at IS NOT NULL AND status = 'mia'")
14
+
15
+ def prototype
16
+ self.path + "(#{self.args.join(', ')})"
17
+ end
13
18
 
14
19
  # Method used by the boss to dispatch an employee
15
20
  def dispatch(boss)
16
21
  mark_as_started
17
- boss.logger.info "Dispatching Job ##{self.id}"
22
+ boss.logger.info "Dispatching Job ##{self.id}: #{self.prototype}"
18
23
 
19
24
  pid = fork do
20
25
  ActiveRecord::Base.connection.reconnect!
21
- $0 = "[job_boss employee] job ##{self.id} #{self.path}(#{self.args.join(', ')})"
26
+ $0 = "[job_boss employee] job ##{self.id} #{self.prototype})"
22
27
  Process.setpriority(Process::PRIO_PROCESS, 0, 19)
23
28
 
24
29
  begin
@@ -35,7 +40,7 @@ module JobBoss
35
40
  sleep(1)
36
41
  end
37
42
 
38
- Boss.logger.info "Job ##{self.id} completed, exiting..."
43
+ boss.logger.info "Job ##{self.id} completed in #{self.time_taken} seconds, exiting..."
39
44
  Kernel.exit
40
45
  end
41
46
  end
@@ -94,6 +99,16 @@ module JobBoss
94
99
  completed_at && (status == 'success')
95
100
  end
96
101
 
102
+ def mark_as_mia
103
+ self.completed_at = Time.now
104
+ self.status = 'mia'
105
+ self.save
106
+ end
107
+
108
+ def mia?
109
+ completed_at && (status == 'mia')
110
+ end
111
+
97
112
  # Has the job been assigned to an employee?
98
113
  def assigned?
99
114
  # If the #assigned? method is being called for but the job hasn't been completed, reload
@@ -137,6 +152,10 @@ module JobBoss
137
152
  Job.uncached do
138
153
  until Job.completed.find_all_by_id(ids).count == jobs.size
139
154
  sleep(sleep_interval)
155
+
156
+ if block_given?
157
+ yield ((Job.where('id in (?)', ids).completed.count.to_f / jobs.size.to_f) * 100.0)
158
+ end
140
159
  end
141
160
  end
142
161
 
@@ -76,6 +76,43 @@ class DaemonTest < ActiveSupport::TestCase
76
76
  assert job.cancelled?
77
77
  assert_not_nil job.cancelled_at
78
78
 
79
+
80
+ # Test recording of MIA jobs
81
+ job = Boss.queue.sleep.sleep_for(20)
82
+
83
+ wait_until_job_assigned(job)
84
+
85
+ assert_pid_running(job.employee_pid)
86
+
87
+ Process.kill(9, job.employee_pid)
88
+
89
+ sleep(1)
90
+
91
+ assert_pid_not_running(job.employee_pid)
92
+
93
+ job.reload
94
+ assert job.mia?
95
+ assert_equal [job.id], Job.mia.collect(&:id)
96
+
97
+ jobs = (0..10).collect do |i|
98
+ job = Boss.queue.sleep.sleep_for(1)
99
+ end
100
+
101
+ progresses = []
102
+ Job.wait_for_jobs(jobs) do |progress|
103
+ # puts progress
104
+ progresses << progress
105
+ end
106
+
107
+ assert_equal progresses, progresses.sort
108
+ assert progresses.all? {|progress| 0.0 <= progress && progress <= 100.0 }
109
+ assert progresses.any? {|progress| progress > 1.0 }
110
+
111
+ # Test deleting of old jobs
112
+
113
+ # Sleep for 1 second so that the upcoming deletions work correctly
114
+ sleep(1)
115
+
79
116
  Job.delete_jobs_before(20.seconds.ago)
80
117
  assert Job.completed.count > 0
81
118
  Job.delete_jobs_before(1.second.ago)
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 5
8
- - 8
9
- version: 0.5.8
7
+ - 6
8
+ - 0
9
+ version: 0.6.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Brian Underwood
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-12-20 00:00:00 -05:00
17
+ date: 2010-12-22 00:00:00 -05:00
18
18
  default_executable: job_boss
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency