delayed_job_monitor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/.DS_Store +0 -0
  2. data/.gitignore +18 -0
  3. data/Gemfile +23 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +57 -0
  6. data/Rakefile +1 -0
  7. data/config.yml +29 -0
  8. data/delayed_job_monitor.gemspec +18 -0
  9. data/delayed_job_monitor_app.rb +7 -0
  10. data/lib/.DS_Store +0 -0
  11. data/lib/delayed_job_monitor/.DS_Store +0 -0
  12. data/lib/delayed_job_monitor/application/.DS_Store +0 -0
  13. data/lib/delayed_job_monitor/application/app.rb +187 -0
  14. data/lib/delayed_job_monitor/application/public/images/poll.png +0 -0
  15. data/lib/delayed_job_monitor/application/public/javascripts/application.js +64 -0
  16. data/lib/delayed_job_monitor/application/public/javascripts/jquery-1.7.1.min.js +4 -0
  17. data/lib/delayed_job_monitor/application/public/javascripts/jquery.relatize_date.js +117 -0
  18. data/lib/delayed_job_monitor/application/public/stylesheets/reset.css +44 -0
  19. data/lib/delayed_job_monitor/application/public/stylesheets/style.css +150 -0
  20. data/lib/delayed_job_monitor/application/views/enqueued.haml +10 -0
  21. data/lib/delayed_job_monitor/application/views/error.haml +2 -0
  22. data/lib/delayed_job_monitor/application/views/failed.haml +14 -0
  23. data/lib/delayed_job_monitor/application/views/job.haml +43 -0
  24. data/lib/delayed_job_monitor/application/views/layout.haml +23 -0
  25. data/lib/delayed_job_monitor/application/views/next_more.haml +6 -0
  26. data/lib/delayed_job_monitor/application/views/overview.haml +110 -0
  27. data/lib/delayed_job_monitor/application/views/pending.haml +9 -0
  28. data/lib/delayed_job_monitor/application/views/queue.haml +13 -0
  29. data/lib/delayed_job_monitor/application/views/servers.haml +16 -0
  30. data/lib/delayed_job_monitor/application/views/workers.haml +15 -0
  31. data/lib/delayed_job_monitor/application/views/working.haml +9 -0
  32. data/lib/delayed_job_monitor/job.rb +31 -0
  33. data/lib/delayed_job_monitor/server.rb +77 -0
  34. data/lib/delayed_job_monitor/version.rb +3 -0
  35. data/lib/delayed_job_monitor/worker.rb +10 -0
  36. data/lib/delayed_job_monitor.rb +85 -0
  37. metadata +81 -0
@@ -0,0 +1,43 @@
1
+ %li.job
2
+ %dl
3
+ %dt ID
4
+ %dd
5
+ %a{:name => job.id}
6
+ %a{:href => "##{job.id}"}=job.id
7
+ %div.controls
8
+ %a{:rel => 'retry', :href => u("requeue/#{job.id}")}Retry
9
+ or
10
+ %a{:rel => 'remove', :href => u("remove/#{job.id}")}Remove
11
+ %dt Priority
12
+ %dd= job.priority
13
+ %dt Attempts
14
+ %dd= job.attempts
15
+ - if job.respond_to?(:queue) && job.queue
16
+ %dt Queue
17
+ %dd
18
+ %a{:href => u("/queue/#{job.queue}")}=job.queue
19
+ -#%dt Description
20
+ -#%dd
21
+ %pre= job.description
22
+ - if job.last_error
23
+ %dt Last Error
24
+ %dd
25
+ %div.backtrace
26
+ %pre= job.last_error[0..100] + '...'
27
+ %a{:href => '#', :class => 'backtrace'} Toggle full message
28
+ %div.backtrace.full.hide
29
+ %pre= job.last_error
30
+ - if job.run_at
31
+ %dt Run At
32
+ %dd.time= job.run_at.rfc822
33
+ - if job.locked_at
34
+ %dt Locked At
35
+ %dd.time= job.locked_at.rfc822
36
+ - if job.locked_by
37
+ %dt Locked By
38
+ %dd= job.locked_by
39
+ - if job.failed_at
40
+ %dt Failed At
41
+ %dd.time= job.failed_at.rfc822
42
+ %dt Created At
43
+ %dd.time= job.created_at.rfc822
@@ -0,0 +1,23 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title Delayed Job Monitor
5
+ %link(rel="stylesheet" type="text/css" href="#{u 'stylesheets/reset.css'}")
6
+ %link(rel="stylesheet" type="text/css" href="#{u 'stylesheets/style.css'}")
7
+ %body
8
+ %div.header
9
+ %ul.nav
10
+ - tabs.each do |tab|
11
+ %li{:class => request.path_info == tab[:path] ? 'current' : ''}
12
+ %a.tab{:href => u(tab[:path])}= tab[:name]
13
+ %div#main
14
+ = yield
15
+ %div#footer
16
+ %p
17
+ Powered & Inspired by
18
+ %a{:href => 'https://github.com/collectiveidea/delayed_job'} delayed_job
19
+ &
20
+ %a{:href => 'https://github.com/ejschmitt/delayed_job_web'} delayed_job_web
21
+ %script{:type => "text/javascript", :src => u("javascripts/jquery-1.7.1.min.js")}
22
+ %script{:type => "text/javascript", :src => u("javascripts/jquery.relatize_date.js")}
23
+ %script{:type => "text/javascript", :src => u("javascripts/application.js")}
@@ -0,0 +1,6 @@
1
+ - if start - per_page >= 0 || start + per_page <= total_size
2
+ %p.pagination
3
+ - if start - per_page >= 0
4
+ %a{:href => "#{current_page}?start=#{start - per_page}", :class => 'less'} &laquo; less
5
+ - if start + per_page < total_size
6
+ %a{:href => "#{current_page}?start=#{start + per_page}", :class => 'more'} more &raquo;
@@ -0,0 +1,110 @@
1
+ .left_col
2
+ .overview
3
+ %h1
4
+ Overview
5
+ %p.sub
6
+ Jobs in the Delayed_Job queue.
7
+ %table.overview
8
+ %tr
9
+ %th Status
10
+ %th Count
11
+ %tr
12
+ %td.status
13
+ %a{:href => u('/enqueued')} Enqueued Jobs
14
+ %td= delayed_job.count
15
+ %tr
16
+ %td.status
17
+ %a{:href => u('/working')} Working Jobs
18
+ %td= delayed_jobs(:working).count
19
+ %tr
20
+ %td.status
21
+ %a{:href => u('/pending')} Pending Jobs
22
+ %td= delayed_jobs(:pending).count
23
+ %tr{:class => delayed_jobs(:failed).count > 0 ? 'failure' : ''}
24
+ %td.status
25
+ %a{:href => u('/failed')} Failed Jobs
26
+ %td= delayed_jobs(:failed).count
27
+ .queues
28
+ %h1
29
+ Queues
30
+ %p.sub
31
+ Jobs by Queue
32
+ %table.overview
33
+ %tr
34
+ -#%th Host
35
+ %th Queue
36
+ %th Count
37
+ %th Priority
38
+ %th Working
39
+ %th Pending
40
+ %th Failed
41
+ - DelayedJobMonitor::Job.select(:queue).map(&:queue).compact.uniq.each do |q|
42
+ %tr
43
+ -#%td= DelayedJobMonitor[:database]["host"].to_s
44
+ %td.status
45
+ %a{:href => u("/queue/#{q}")}= "#{q.split("_").map(&:capitalize).join(" ")}"
46
+ %td= delayed_job.where(:queue=>q).count
47
+ %td= delayed_job.where(:queue=>q).select(:priority).map(&:priority).uniq.sort.join(", ")
48
+ %td= delayed_job.where(:queue=>q).where("locked_at IS NOT NULL").count
49
+ %td= delayed_job.where(:queue=>q).where("locked_at IS NULL AND last_error IS NULL").count
50
+ %td{:style => "color:red;"}= delayed_job.where(:queue=>q).where("last_error IS NOT NULL").count
51
+ .workers
52
+ %h1 Workers
53
+ %p.sub
54
+ Delayed Jobs workers
55
+ %table.overview
56
+ %tr
57
+ %th Host
58
+ %th Worker
59
+ %th PID
60
+ %th CPU %
61
+ %th Mem %
62
+ %th Started
63
+ %th Run Time
64
+ - DelayedJobMonitor::Server.servers.each do |server|
65
+ -server.delayed_job_workers.each do |worker|
66
+ %tr
67
+ %td= worker.host
68
+ %td= worker.name.split(".").last
69
+ %td= worker.pid
70
+ %td= worker.cpu
71
+ %td= worker.mem
72
+ %td= worker.started
73
+ %td= worker.run_time
74
+ = poll
75
+ .right_col
76
+ .logs
77
+ %h1 Logs
78
+ %p.sub
79
+ Delayed Jobs Logs
80
+ .log_box
81
+ \> WELCOME
82
+ .stats
83
+ %h1 Stats
84
+ %p.sub
85
+ Delayed Job Stats
86
+ %table.overview
87
+ %tr
88
+ %th
89
+ %th Today
90
+ %th This Week
91
+ %th This Month
92
+ %th All Time
93
+ %tr
94
+ %td Completed Jobs
95
+ %td 0
96
+ %td 0
97
+ %td 0
98
+ %td 0
99
+ %tr
100
+ %td Deleted Jobs
101
+ %td 0
102
+ %td 0
103
+ %td 0
104
+ %td 0
105
+ %tr
106
+ %td Failed Jobs
107
+ %td 0
108
+ %td 0
109
+ %td 0
110
+ %td 0
@@ -0,0 +1,9 @@
1
+ %h1
2
+ Pending
3
+ %p.sub
4
+ The list below contains jobs currently being processed.
5
+ %p.sub= "Showing #{start} to #{start + per_page} of #{@all_jobs.count} pending jobs."
6
+ %ul.job
7
+ - @jobs.each do |job|
8
+ = partial :job, {:job => job}
9
+ = partial :next_more, :start => start, :total_size => @all_jobs.count, :per_page => per_page
@@ -0,0 +1,13 @@
1
+ %h1="#{params[:queue].split("_").map(&:capitalize).join(" ")}"
2
+ - if @jobs.any?
3
+ %form{:method => 'POST', :action => u('failed/clear')}
4
+ %input{:type => 'submit', :value => 'Clear Failed Jobs'}
5
+ %form{:method => 'POST', :action => u('update/all')}
6
+ %input{:type => 'submit', :value => 'Retry Failed Jobs'}
7
+ %p.sub
8
+ The list below contains jobs in the #{params[:queue].split("_").map(&:capitalize).join(" ")} queue.
9
+ %p.sub= "Showing #{start} to #{start + per_page} of #{@all_jobs} pending jobs."
10
+ %ul.job
11
+ - @jobs.each do |job|
12
+ = partial :job, {:job => job}
13
+ = partial :next_more, :start => start, :total_size => @all_jobs, :per_page => per_page
@@ -0,0 +1,16 @@
1
+ %h1= @servers.first.name
2
+ / %h1 Servers
3
+ / %p.sub
4
+ / Servers running Delayed Jobs worker daemons
5
+ / - if @servers.any?
6
+ / %ul.server
7
+ / - @servers.each do |server|
8
+ / %li= server.host
9
+ / %li= server.name
10
+ / %li= server.pid
11
+ / %li= server.cpu
12
+ / %li= server.mem
13
+ / %li= server.started
14
+ / %li= server.run_time
15
+ / - else
16
+ / %p There are no Delayed Jobs servers running on any hosts.
@@ -0,0 +1,15 @@
1
+ %h1 Workers
2
+ %p.sub
3
+ Delayed Job workers running on the configured hosts
4
+ - if @workers.any?
5
+ %ul.worker
6
+ - @workers.each do |worker|
7
+ %li= worker.host
8
+ %li= worker.name
9
+ %li= worker.pid
10
+ %li= worker.cpu
11
+ %li= worker.mem
12
+ %li= worker.started
13
+ %li= worker.run_time
14
+ - else
15
+ %p There are no Delayed Jobs workers running on any hosts.
@@ -0,0 +1,9 @@
1
+ %h1
2
+ Working
3
+ %p.sub
4
+ The list below contains jobs currently being processed.
5
+ %p.sub= "Showing #{start} to #{start + per_page} of #{@all_jobs.count} working jobs."
6
+ %ul.job
7
+ - @jobs.each do |job|
8
+ = partial :job, {:job => job}
9
+ = partial :next_more, :start => start, :total_size => @all_jobs.count, :per_page => per_page
@@ -0,0 +1,31 @@
1
+ #delayed_job_monitor.establish_connection
2
+
3
+ module DelayedJobMonitor
4
+ class Job < ActiveRecord::Base
5
+ self.table_name = "delayed_jobs"
6
+
7
+ def self.queues
8
+ @queues = delayed_job_monitor::Job.select(:queue).map(&:queue).compact.uniq.sort
9
+ return @queues
10
+ end
11
+
12
+ def host
13
+ unless DelayedJobMonitor[:database]["host"].blank?
14
+ return DelayedJobMonitor[:database]["host"]
15
+ else
16
+ return "localhost"
17
+ end
18
+ end
19
+
20
+ def description
21
+ details = {}
22
+ parsed_handler = self.handler.split(/\n/)
23
+ parsed_handler.map{|x| details[x.split(":")[0].strip.split(/\//).last] = x.split(/\:|\/|\s/).last.strip unless x.blank?}
24
+ target_class = details["ActiveRecord"]
25
+ target_id = details["id"].to_s.gsub(/\W/,"").to_i if details["id"].present?
26
+ performable_class = details["object"] if details["object"].present?
27
+ performable_method = details["method_name"] if details["method_name"].present?
28
+ return "Perform #{performable_class}:#{performable_method} on #{target_class}##{target_id}"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,77 @@
1
+ require 'net/ssh'
2
+ require 'hashie'
3
+
4
+ module DelayedJobMonitor
5
+ class Server
6
+ @@instance_collector = []
7
+ def initialize(name="default",host="localhost",rails_path=nil,username=nil,password=nil)
8
+ unless host == "localhost"
9
+ @connection = Net::SSH.start(host,username,:password=>password)
10
+ @username = username
11
+ else
12
+ @connection = nil
13
+ end
14
+ @rails_path = rails_path
15
+ @name = name
16
+ @host = host
17
+ @@instance_collector << self
18
+ end
19
+
20
+ def self.servers
21
+ return @@instance_collector
22
+ end
23
+
24
+ def connection
25
+ @connection
26
+ end
27
+
28
+ def close_connection
29
+ connection.close
30
+ end
31
+
32
+ def host
33
+ @host
34
+ end
35
+
36
+ def name
37
+ @name
38
+ end
39
+
40
+ def rails_path
41
+ @rails_path
42
+ end
43
+
44
+ # def tail_log
45
+ # log_file = File.open( "tmp/logs/delayed_job_#{host.gsub(/\W/,"_")}.log","w")
46
+ # log_file << connection.exec!("tail -f /var/www/contently/log/delayed_job.log")
47
+ # log_file.close
48
+ # end
49
+
50
+ def delayed_job_workers
51
+ @worker_list = []
52
+ if self.connection
53
+ workers = connection.exec!("ps aux").split(/\n/).map{|x| x.split(/\s+/) if x.split(/\s+/).last.match("job")}.compact
54
+ else
55
+ workers = %x{ps aux}.split(/\n/).map{|x| x.split(/\s+/) if x.split(/\s+/).last.match("job")}.compact
56
+ end
57
+ if workers.any?
58
+ workers.each do |wkr|
59
+ @worker_list << Hashie::Mash.new({:host=>host,:name=>wkr.last,:pid=>wkr[1],:cpu=>wkr[2],:mem=>wkr[3],:started=>wkr[8],:run_time=>wkr[9]})
60
+ end
61
+ return @worker_list
62
+ else
63
+ return nil
64
+ end
65
+ end
66
+
67
+ def stop_workers(env=production)
68
+ p "Attempting to stop delayed jobs workers..."
69
+ command = connection.exec!("#{rails_path}/script/delayed_job stop")
70
+ return command #get the status code as a string
71
+ end
72
+
73
+ def start_workers(env=production)
74
+ p "Attempting to stop delayed jobs workers..."
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,3 @@
1
+ module DelayedJobMonitor
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,10 @@
1
+ require 'hashie'
2
+ require 'delayed_job'
3
+ require 'delayed/command'
4
+
5
+ module DelayedJobMonitor
6
+ class Worker < Delayed::Worker
7
+ # for extending/mapping to the DJ Worker class. Might not need
8
+ end
9
+
10
+ end
@@ -0,0 +1,85 @@
1
+ require 'active_record'
2
+ require 'yaml'
3
+ require './lib/delayed_job_monitor/worker'
4
+ require './lib/delayed_job_monitor/server'
5
+ require './lib/delayed_job_monitor/application/app'
6
+ require './lib/delayed_job_monitor/job'
7
+ require './lib/delayed_job_monitor/version'
8
+
9
+ module DelayedJobMonitor
10
+ def self.[](key)
11
+ unless @config
12
+ @config = YAML.load_file("config.yml").symbolize_keys
13
+ end
14
+ @config[key.to_sym]
15
+ end
16
+
17
+ def self.[]=(key, value)
18
+ @config[key.to_sym] = value
19
+ end
20
+
21
+ def self.establish_connection
22
+ begin
23
+ if DelayedJobMonitor[:database]["host"].nil?
24
+ raise "No database connection defined in config.yml"
25
+ else
26
+ if defined? connection
27
+ p "There is already a DB connection locally...closing"
28
+ DelayedJobMonitor.connection.disconnect!
29
+ DelayedJobMonitor.connection.connection.close
30
+ ActiveRecord::Base.clear_active_connections!
31
+ ActiveRecord::Base.clear_reloadable_connections!
32
+ end
33
+ db = DelayedJobMonitor[:database]
34
+ connection = ActiveRecord::Base.establish_connection(:adapter => db["adapter"],:database => db["database"],:host=>db["host"],:port=>db["port"],:username=>db["username"],:password=>db["password"],:encoding => "utf8",:template=>"template0")
35
+ return connection
36
+ end
37
+ rescue
38
+ raise "ERROR: Could not connect to the Delayed::Job database. REASON: #{$!}. Please check your configuration settings."
39
+ end
40
+ end
41
+
42
+ def self.delayed_job_running_locally?
43
+ local_delayed_jobs = %x{ps aux}.split(/\n/).map{|x| x.split(/\s+/) if x.split(/\s+/).last.match("job")}.compact
44
+ if local_delayed_jobs.empty?
45
+ return false
46
+ else
47
+ return true
48
+ end
49
+ end
50
+
51
+ def self.stand_alone_mode?
52
+ !ENV["RAILS_ENV"].present?
53
+ end
54
+
55
+ def self.initialize_servers
56
+ DelayedJobMonitor[:hosts].each do |host|
57
+ DelayedJobMonitor::Server.new(host["name"],host["host"],host["rails_path"],host["username"],host["password"])
58
+ end
59
+ if delayed_job_running_locally?
60
+ DelayedJobMonitor::Server.new
61
+ end
62
+ return DelayedJobMonitor::Server.servers
63
+ end
64
+
65
+ def self.start!
66
+ DelayedJobMonitor.establish_connection
67
+ DelayedJobMonitor.initialize_servers
68
+ DelayedJobMonitor::App.run!
69
+ end
70
+ end
71
+
72
+ #I know this is terrible, but I want to use the Delayed Job methods without rewriting them from scratch
73
+ if DelayedJobMonitor.stand_alone_mode?
74
+ class Rails
75
+ def self.root
76
+ return Pathname.new(Dir.pwd)
77
+ end
78
+
79
+ def self.logger
80
+ return nil
81
+ end
82
+ end
83
+ end
84
+
85
+ DelayedJobMonitor.establish_connection
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: delayed_job_monitor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dan Barrett
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-16 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: An Adminstrative tool for Delayed Jobs
15
+ email:
16
+ - dbarrett83@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .DS_Store
22
+ - .gitignore
23
+ - Gemfile
24
+ - LICENSE.txt
25
+ - README.md
26
+ - Rakefile
27
+ - config.yml
28
+ - delayed_job_monitor.gemspec
29
+ - delayed_job_monitor_app.rb
30
+ - lib/.DS_Store
31
+ - lib/delayed_job_monitor.rb
32
+ - lib/delayed_job_monitor/.DS_Store
33
+ - lib/delayed_job_monitor/application/.DS_Store
34
+ - lib/delayed_job_monitor/application/app.rb
35
+ - lib/delayed_job_monitor/application/public/images/poll.png
36
+ - lib/delayed_job_monitor/application/public/javascripts/application.js
37
+ - lib/delayed_job_monitor/application/public/javascripts/jquery-1.7.1.min.js
38
+ - lib/delayed_job_monitor/application/public/javascripts/jquery.relatize_date.js
39
+ - lib/delayed_job_monitor/application/public/stylesheets/reset.css
40
+ - lib/delayed_job_monitor/application/public/stylesheets/style.css
41
+ - lib/delayed_job_monitor/application/views/enqueued.haml
42
+ - lib/delayed_job_monitor/application/views/error.haml
43
+ - lib/delayed_job_monitor/application/views/failed.haml
44
+ - lib/delayed_job_monitor/application/views/job.haml
45
+ - lib/delayed_job_monitor/application/views/layout.haml
46
+ - lib/delayed_job_monitor/application/views/next_more.haml
47
+ - lib/delayed_job_monitor/application/views/overview.haml
48
+ - lib/delayed_job_monitor/application/views/pending.haml
49
+ - lib/delayed_job_monitor/application/views/queue.haml
50
+ - lib/delayed_job_monitor/application/views/servers.haml
51
+ - lib/delayed_job_monitor/application/views/workers.haml
52
+ - lib/delayed_job_monitor/application/views/working.haml
53
+ - lib/delayed_job_monitor/job.rb
54
+ - lib/delayed_job_monitor/server.rb
55
+ - lib/delayed_job_monitor/version.rb
56
+ - lib/delayed_job_monitor/worker.rb
57
+ homepage: http://www.contently.com
58
+ licenses: []
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubyforge_project:
77
+ rubygems_version: 1.8.24
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Manage all your delayed jobs
81
+ test_files: []