delayed_job_mongoid_web 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. data/.document +5 -0
  2. data/Gemfile +15 -0
  3. data/LICENSE.txt +20 -0
  4. data/README.markdown +61 -0
  5. data/Rakefile +53 -0
  6. data/VERSION +1 -0
  7. data/bin/delayed_job_mongoid_web +10 -0
  8. data/delayed_job_mongoid_web.gemspec +95 -0
  9. data/lib/delayed_job_mongoid_web/application/app.rb +156 -0
  10. data/lib/delayed_job_mongoid_web/application/public/images/poll.png +0 -0
  11. data/lib/delayed_job_mongoid_web/application/public/javascripts/application.js +64 -0
  12. data/lib/delayed_job_mongoid_web/application/public/javascripts/jquery-1.7.1.min.js +4 -0
  13. data/lib/delayed_job_mongoid_web/application/public/javascripts/jquery.relatize_date.js +117 -0
  14. data/lib/delayed_job_mongoid_web/application/public/stylesheets/reset.css +44 -0
  15. data/lib/delayed_job_mongoid_web/application/public/stylesheets/style.css +89 -0
  16. data/lib/delayed_job_mongoid_web/application/views/enqueued.haml +10 -0
  17. data/lib/delayed_job_mongoid_web/application/views/error.haml +2 -0
  18. data/lib/delayed_job_mongoid_web/application/views/failed.haml +14 -0
  19. data/lib/delayed_job_mongoid_web/application/views/job.haml +42 -0
  20. data/lib/delayed_job_mongoid_web/application/views/layout.haml +23 -0
  21. data/lib/delayed_job_mongoid_web/application/views/next_more.haml +6 -0
  22. data/lib/delayed_job_mongoid_web/application/views/overview.haml +25 -0
  23. data/lib/delayed_job_mongoid_web/application/views/pending.haml +12 -0
  24. data/lib/delayed_job_mongoid_web/application/views/stats.haml +20 -0
  25. data/lib/delayed_job_mongoid_web/application/views/working.haml +9 -0
  26. data/lib/delayed_job_mongoid_web.rb +1 -0
  27. data/test/helper.rb +18 -0
  28. data/test/test_delayed_job_mongoid_web.rb +30 -0
  29. metadata +238 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+ gem "sinatra", '>= 0.9.2'
3
+ gem "haml", '~> 3.1.3'
4
+ gem 'activerecord', '> 3.0.0'
5
+ gem 'mongoid', '> 3.0.0'
6
+ gem 'delayed_job_mongoid', '~> 2.0.0'
7
+ gem 'rdoc'
8
+
9
+ group :development do
10
+ gem "shoulda", ">= 0"
11
+ gem "bundler", "> 1.0.0"
12
+ gem "jeweler", "~> 1.6.4"
13
+ gem "simplecov", "~> 0.7.1"
14
+ gem "rack-test", ">= 0"
15
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Erick Schmitt
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,61 @@
1
+ delayed_job_web
2
+ ===============
3
+
4
+ A [resque][0] inspired (read: stolen) interface for delayed_job.
5
+ This gem is written to work with rails 3 applications using
6
+ activerecord.
7
+
8
+ Some features:
9
+
10
+ * Easily view jobs enqueued, working, pending, and failed.
11
+ * Queue any single job. or all pending jobs, to run immediately.
12
+ * Remove a failed job, or easily remove all failed jobs.
13
+ * Watch delayed_job operation with live ajax polling.
14
+
15
+ Quick Start For Rails 3 Applications
16
+ ------------------------------------
17
+
18
+ Add the dependency to your Gemfile
19
+
20
+ ```ruby
21
+ gem "delayed_job_mongoid_web"
22
+ ```
23
+
24
+ Install it...
25
+
26
+ ```ruby
27
+ bundle
28
+ ```
29
+
30
+ Add a route to your application for accessing the interface
31
+
32
+ ```ruby
33
+ match "/delayed_job" => DelayedJobMongoidWeb, :anchor => false
34
+ ```
35
+
36
+ You probably want to password protect the interface, an easy way is to add something like this your config.ru file
37
+
38
+ ```ruby
39
+ if Rails.env.production?
40
+ DelayedJobMongoidWeb.use Rack::Auth::Basic do |username, password|
41
+ username == 'username' && password == 'password'
42
+ end
43
+ end
44
+ ```
45
+
46
+ The Interface - Yea, a ripoff of resque-web
47
+ ------------------------------------
48
+
49
+ ![Screen shot](http://dl.dropbox.com/u/1506097/Screenshots/delayed_job_web_1.png)
50
+
51
+ ![Screen shot](http://dl.dropbox.com/u/1506097/Screenshots/delayed_job_web_2.png)
52
+
53
+
54
+ Author
55
+ ------
56
+
57
+ Erick Schmitt - [@ejschmitt][1]
58
+
59
+
60
+ [0]: https://github.com/defunkt/resque
61
+ [1]: http://twitter.com/ejschmitt
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "delayed_job_web"
18
+ gem.homepage = "http://github.com/ejschmitt/delayed_job_web"
19
+ gem.license = "MIT"
20
+ gem.summary = "Web interface for delayed_job"
21
+ gem.description = "Web interface for delayed_job inspired by resque"
22
+ gem.email = "ejschmitt@gmail.com"
23
+ gem.authors = ["Erick Schmitt"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ # require 'rcov/rcovtask'
36
+ # Rcov::RcovTask.new do |test|
37
+ # test.libs << 'test'
38
+ # test.pattern = 'test/**/test_*.rb'
39
+ # test.verbose = true
40
+ # test.rcov_opts << '--exclude "gems/*"'
41
+ # end
42
+
43
+ task :default => :test
44
+
45
+ require 'rdoc/task'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "delayed_job_web #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.1.2
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ begin
4
+ require 'delayed_job_web/application/app.rb'
5
+ rescue LoadError => e
6
+ require 'rubygems'
7
+ path = File.expand_path '../../lib', __FILE__
8
+ $:.unshift(path) if File.directory?(path) && !$:.include?(path)
9
+ require 'delayed_job_web/application/app.rb'
10
+ end
@@ -0,0 +1,95 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "delayed_job_mongoid_web"
8
+ s.version = "1.1.3"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Erick Schmitt", "Rob Dingwell"]
12
+ s.date = "2012-05-18"
13
+ s.description = "Web interface for delayed_job inspired by resque"
14
+ s.email = "ejschmitt@gmail.com"
15
+ s.executables = ["delayed_job_mongoid_web"]
16
+ s.extra_rdoc_files = [
17
+ "LICENSE.txt",
18
+ "README.markdown"
19
+ ]
20
+ s.files = [
21
+ ".document",
22
+ "Gemfile",
23
+ "LICENSE.txt",
24
+ "README.markdown",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "bin/delayed_job_mongoid_web",
28
+ "delayed_job_mongoid_web.gemspec",
29
+ "lib/delayed_job_mongoid_web.rb",
30
+ "lib/delayed_job_mongoid_web/application/app.rb",
31
+ "lib/delayed_job_mongoid_web/application/public/images/poll.png",
32
+ "lib/delayed_job_mongoid_web/application/public/javascripts/application.js",
33
+ "lib/delayed_job_mongoid_web/application/public/javascripts/jquery-1.7.1.min.js",
34
+ "lib/delayed_job_mongoid_web/application/public/javascripts/jquery.relatize_date.js",
35
+ "lib/delayed_job_mongoid_web/application/public/stylesheets/reset.css",
36
+ "lib/delayed_job_mongoid_web/application/public/stylesheets/style.css",
37
+ "lib/delayed_job_mongoid_web/application/views/enqueued.haml",
38
+ "lib/delayed_job_mongoid_web/application/views/error.haml",
39
+ "lib/delayed_job_mongoid_web/application/views/failed.haml",
40
+ "lib/delayed_job_mongoid_web/application/views/job.haml",
41
+ "lib/delayed_job_mongoid_web/application/views/layout.haml",
42
+ "lib/delayed_job_mongoid_web/application/views/next_more.haml",
43
+ "lib/delayed_job_mongoid_web/application/views/overview.haml",
44
+ "lib/delayed_job_mongoid_web/application/views/pending.haml",
45
+ "lib/delayed_job_mongoid_web/application/views/stats.haml",
46
+ "lib/delayed_job_mongoid_web/application/views/working.haml",
47
+ "test/helper.rb",
48
+ "test/test_delayed_job_mongoid_web.rb"
49
+ ]
50
+ s.homepage = "http://github.com/rdingwell/delayed_job_mongoid_web"
51
+ s.licenses = ["MIT"]
52
+ s.require_paths = ["lib"]
53
+ s.rubygems_version = "1.8.22"
54
+ s.summary = "Web interface for delayed_job"
55
+
56
+ if s.respond_to? :specification_version then
57
+ s.specification_version = 3
58
+
59
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
60
+ s.add_runtime_dependency(%q<sinatra>, [">= 0.9.2"])
61
+ s.add_runtime_dependency(%q<haml>, ["~> 3.1.3"])
62
+ s.add_runtime_dependency(%q<activerecord>, ["> 3.0.0"])
63
+ s.add_runtime_dependency(%q<delayed_job>, ["> 2.0.3"])
64
+ s.add_runtime_dependency(%q<rdoc>, [">= 0"])
65
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
66
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
67
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
68
+ s.add_development_dependency(%q<rcov>, [">= 0"])
69
+ s.add_development_dependency(%q<rack-test>, [">= 0"])
70
+ else
71
+ s.add_dependency(%q<sinatra>, [">= 0.9.2"])
72
+ s.add_dependency(%q<haml>, ["~> 3.1.3"])
73
+ s.add_dependency(%q<activerecord>, ["> 3.0.0"])
74
+ s.add_dependency(%q<delayed_job>, ["> 2.0.3"])
75
+ s.add_dependency(%q<rdoc>, [">= 0"])
76
+ s.add_dependency(%q<shoulda>, [">= 0"])
77
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
78
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
79
+ s.add_dependency(%q<rcov>, [">= 0"])
80
+ s.add_dependency(%q<rack-test>, [">= 0"])
81
+ end
82
+ else
83
+ s.add_dependency(%q<sinatra>, [">= 0.9.2"])
84
+ s.add_dependency(%q<haml>, ["~> 3.1.3"])
85
+ s.add_dependency(%q<activerecord>, ["> 3.0.0"])
86
+ s.add_dependency(%q<delayed_job>, ["> 2.0.3"])
87
+ s.add_dependency(%q<rdoc>, [">= 0"])
88
+ s.add_dependency(%q<shoulda>, [">= 0"])
89
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
90
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
91
+ s.add_dependency(%q<rcov>, [">= 0"])
92
+ s.add_dependency(%q<rack-test>, [">= 0"])
93
+ end
94
+ end
95
+
@@ -0,0 +1,156 @@
1
+ require 'sinatra/base'
2
+ require 'active_support'
3
+ require 'active_record'
4
+ require 'delayed_job'
5
+ require 'haml'
6
+
7
+ class DelayedJobMongoidWeb < Sinatra::Base
8
+ set :root, File.dirname(__FILE__)
9
+ set :static, true
10
+ set :public_folder, File.expand_path('../public', __FILE__)
11
+ set :views, File.expand_path('../views', __FILE__)
12
+ set :haml, { :format => :html5 }
13
+
14
+ def current_page
15
+ url_path request.path_info.sub('/','')
16
+ end
17
+
18
+ def start
19
+ params[:start].to_i
20
+ end
21
+
22
+ def per_page
23
+ 20
24
+ end
25
+
26
+ def url_path(*path_parts)
27
+ [ path_prefix, path_parts ].join("/").squeeze('/')
28
+ end
29
+ alias_method :u, :url_path
30
+
31
+ def path_prefix
32
+ request.env['SCRIPT_NAME']
33
+ end
34
+
35
+ def tabs
36
+ [
37
+ {:name => 'Overview', :path => '/overview'},
38
+ {:name => 'Enqueued', :path => '/enqueued'},
39
+ {:name => 'Working', :path => '/working'},
40
+ {:name => 'Pending', :path => '/pending'},
41
+ {:name => 'Failed', :path => '/failed'},
42
+ {:name => 'Stats', :path => '/stats'}
43
+ ]
44
+ end
45
+
46
+ def delayed_job
47
+ begin
48
+ Delayed::Job
49
+ rescue
50
+ false
51
+ end
52
+ end
53
+
54
+ get '/overview' do
55
+ if delayed_job
56
+ haml :overview
57
+ else
58
+ @message = "Unable to connected to Delayed::Job database"
59
+ haml :error
60
+ end
61
+ end
62
+
63
+ get '/stats' do
64
+ haml :stats
65
+ end
66
+
67
+ %w(enqueued working pending failed).each do |page|
68
+ get "/#{page}" do
69
+ @jobs = delayed_jobs(page.to_sym).order_by([:created_at, :desc]).skip(start).limit(per_page)
70
+ @all_jobs = delayed_jobs(page.to_sym)
71
+ haml page.to_sym
72
+ end
73
+ end
74
+
75
+ get "/remove/:id" do
76
+ delayed_job.find(params[:id]).delete
77
+ redirect back
78
+ end
79
+
80
+ get "/requeue/:id" do
81
+ job = delayed_job.find(params[:id])
82
+ job.update_attributes(:run_at => Time.now, :failed_at => nil)
83
+ redirect back
84
+ end
85
+
86
+ post "/failed/clear" do
87
+ delayed_job.destroy_all(delayed_job_sql(:failed))
88
+ redirect u('failed')
89
+ end
90
+
91
+ post "/requeue/all" do
92
+ delayed_jobs(:failed).update_all(:run_at => Time.now, :failed_at => nil)
93
+ redirect back
94
+ end
95
+
96
+ def delayed_jobs(type)
97
+ delayed_job_filter(delayed_job,type)
98
+ end
99
+
100
+ def delayed_job_filter(crit, type)
101
+ case type
102
+ when :enqueued
103
+ crit.where({})
104
+ when :working
105
+ crit.where({:locked_at.ne =>nil }) #'locked_at is not null'
106
+ when :failed
107
+ crit.where({:last_error.ne => nil }) # 'last_error is not null'
108
+ when :pending
109
+ crit.where({attempts: 0})
110
+ end
111
+ end
112
+
113
+ get "/?" do
114
+ redirect u(:overview)
115
+ end
116
+
117
+ def partial(template, local_vars = {})
118
+ @partial = true
119
+ haml(template.to_sym, {:layout => false}, local_vars)
120
+ ensure
121
+ @partial = false
122
+ end
123
+
124
+ %w(overview enqueued working pending failed stats) .each do |page|
125
+ get "/#{page}.poll" do
126
+ show_for_polling(page)
127
+ end
128
+
129
+ get "/#{page}/:id.poll" do
130
+ show_for_polling(page)
131
+ end
132
+ end
133
+
134
+ def poll
135
+ if @polling
136
+ text = "Last Updated: #{Time.now.strftime("%H:%M:%S")}"
137
+ else
138
+ text = "<a href='#{u(request.path_info)}.poll' rel='poll'>Live Poll</a>"
139
+ end
140
+ "<p class='poll'>#{text}</p>"
141
+ end
142
+
143
+ def show_for_polling(page)
144
+ content_type "text/html"
145
+ @polling = true
146
+ # show(page.to_sym, false).gsub(/\s{1,}/, ' ')
147
+ @jobs = delayed_jobs(page.to_sym)
148
+ haml(page.to_sym, {:layout => false})
149
+ end
150
+
151
+ end
152
+
153
+ # Run the app!
154
+ #
155
+ # puts "Hello, you're running delayed_job_web"
156
+ # DelayedJobWeb.run!
@@ -0,0 +1,64 @@
1
+ $(function() {
2
+ var poll_interval = 3;
3
+
4
+ var relatizer = function(){
5
+ var dt = $(this).text(), relatized = $.relatizeDate(this)
6
+ if ($(this).parents("a").length > 0 || $(this).is("a")) {
7
+ $(this).relatizeDate()
8
+ if (!$(this).attr('title')) {
9
+ $(this).attr('title', dt)
10
+ }
11
+ } else {
12
+ $(this)
13
+ .text('')
14
+ .append( $('<a href="#" class="toggle_format" title="' + dt + '" />')
15
+ .append('<span class="date_time">' + dt +
16
+ '</span><span class="relatized_time">' +
17
+ relatized + '</span>') )
18
+ }
19
+ };
20
+
21
+ $('.time').each(relatizer);
22
+
23
+ $('.time a.toggle_format .date_time').hide();
24
+
25
+ var format_toggler = function(){
26
+ $('.time a.toggle_format span').toggle();
27
+ $(this).attr('title', $('span:hidden',this).text());
28
+ return false;
29
+ };
30
+
31
+ $('.time a.toggle_format').click(format_toggler);
32
+
33
+ $('ul li.job').hover(function() {
34
+ $(this).addClass('hover');
35
+ }, function() {
36
+ $(this).removeClass('hover');
37
+ })
38
+
39
+ $('a.backtrace').click(function (e) {
40
+ e.preventDefault();
41
+ if($(this).prev('div.backtrace:visible').length > 0) {
42
+ $(this).next('div.backtrace').show();
43
+ $(this).prev('div.backtrace').hide();
44
+ } else {
45
+ $(this).next('div.backtrace').hide();
46
+ $(this).prev('div.backtrace').show();
47
+ }
48
+ });
49
+
50
+ $('a[rel=poll]').click(function(e) {
51
+ e.preventDefault();
52
+ var href = $(this).attr('href')
53
+ $(this).parent().text('Starting...')
54
+ $("#main").addClass('polling')
55
+
56
+ setInterval(function() {
57
+ $.ajax({dataType: 'text', type: 'get', url: href, success: function(data) {
58
+ $('#main').html(data);
59
+ }})
60
+ }, poll_interval * 1000)
61
+
62
+ return false
63
+ })
64
+ })