delayed_job_monitor 0.0.1

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.
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: []