diff --git a/app/jobs/scheduled/weekly.rb b/app/jobs/scheduled/weekly.rb
index 613833ff51..ffce8c1d24 100644
--- a/app/jobs/scheduled/weekly.rb
+++ b/app/jobs/scheduled/weekly.rb
@@ -11,6 +11,7 @@ module Jobs
Post.calculate_avg_time
Topic.calculate_avg_time
ScoreCalculator.new.calculate
+ SchedulerStat.purge_old
Draft.cleanup!
end
end
diff --git a/app/models/scheduler_stat.rb b/app/models/scheduler_stat.rb
new file mode 100644
index 0000000000..55dc8fda6a
--- /dev/null
+++ b/app/models/scheduler_stat.rb
@@ -0,0 +1,20 @@
+class SchedulerStat < ActiveRecord::Base
+ def self.purge_old
+ where('started_at < ?', 3.months.ago).delete_all
+ end
+end
+
+# == Schema Information
+#
+# Table name: scheduler_stats
+#
+# id :integer not null, primary key
+# name :string not null
+# hostname :string not null
+# pid :integer not null
+# duration_ms :integer
+# live_slots_start :integer
+# live_slots_finish :integer
+# started_at :datetime not null
+# success :boolean
+#
diff --git a/db/migrate/20160530003739_create_scheduler_stats.rb b/db/migrate/20160530003739_create_scheduler_stats.rb
new file mode 100644
index 0000000000..04cfdca817
--- /dev/null
+++ b/db/migrate/20160530003739_create_scheduler_stats.rb
@@ -0,0 +1,14 @@
+class CreateSchedulerStats < ActiveRecord::Migration
+ def change
+ create_table :scheduler_stats do |t|
+ t.string :name, null: false
+ t.string :hostname, null: false
+ t.integer :pid, null: false
+ t.integer :duration_ms
+ t.integer :live_slots_start
+ t.integer :live_slots_finish
+ t.datetime :started_at, null: false
+ t.boolean :success
+ end
+ end
+end
diff --git a/lib/scheduler/manager.rb b/lib/scheduler/manager.rb
index 78d1de7fa4..0607804258 100644
--- a/lib/scheduler/manager.rb
+++ b/lib/scheduler/manager.rb
@@ -50,6 +50,14 @@ module Scheduler
Discourse.handle_job_exception(ex, {message: "Scheduling manager orphan rescheduler"})
end
+ def hostname
+ @hostname ||= begin
+ `hostname`
+ rescue
+ "unknown"
+ end
+ end
+
def process_queue
klass = @queue.deq
# hack alert, I need to both deq and set @running atomically.
@@ -57,9 +65,17 @@ module Scheduler
failed = false
start = Time.now.to_f
info = @mutex.synchronize { @manager.schedule_info(klass) }
+ stat = nil
begin
info.prev_result = "RUNNING"
@mutex.synchronize { info.write! }
+ stat = SchedulerStat.create!(
+ name: klass.to_s,
+ hostname: hostname,
+ pid: Process.pid,
+ started_at: Time.zone.now,
+ live_slots_start: GC.stat[:heap_live_slots]
+ )
klass.new.perform
rescue Jobs::HandledExceptionWrapper
# Discourse.handle_exception was already called, and we don't have any extra info to give
@@ -72,6 +88,11 @@ module Scheduler
info.prev_duration = duration
info.prev_result = failed ? "FAILED" : "OK"
info.current_owner = nil
+ stat.update_columns(
+ duration_ms: duration,
+ live_slots_finish: GC.stat[:heap_live_slots],
+ success: !failed
+ )
attempts(3) do
@mutex.synchronize { info.write! }
end
diff --git a/lib/scheduler/views/history.erb b/lib/scheduler/views/history.erb
new file mode 100644
index 0000000000..f6c8f5c92f
--- /dev/null
+++ b/lib/scheduler/views/history.erb
@@ -0,0 +1,45 @@
+Scheduler History
+
| Job Name | +Hostname:Pid | +Live Slots delta | +Started At | +Duration (ms) | ++ + + <% @scheduler_stats.each do |stat| %> + |
|---|---|---|---|---|---|
| <%= stat.name %> | +<%= stat.hostname %>:<%= stat.pid %> | ++ <% if stat.live_slots_start && stat.live_slots_finish %> + <%= stat.live_slots_finish - stat.live_slots_start %> + <% end %> + | +<%= relative_time stat.started_at %> | +<%= stat.duration_ms %> | ++ <% if !stat.success %> + FAILED + <% end %> + | +