qujo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +3 -0
  3. data/Rakefile +38 -0
  4. data/app/assets/javascripts/qujo/application.js +15 -0
  5. data/app/assets/javascripts/qujo/qujo.js +124 -0
  6. data/app/assets/stylesheets/qujo/application.css +13 -0
  7. data/app/controllers/qujo/application_controller.rb +3 -0
  8. data/app/controllers/qujo/jobs_controller.rb +175 -0
  9. data/app/helpers/qujo/application_helper.rb +4 -0
  10. data/app/views/qujo/common/_bootstrap.html.erb +29 -0
  11. data/app/views/qujo/jobs/_form.html.erb +14 -0
  12. data/app/views/qujo/jobs/edit.html.erb +9 -0
  13. data/app/views/qujo/jobs/index.html.erb +54 -0
  14. data/app/views/qujo/jobs/new.html.erb +5 -0
  15. data/app/views/qujo/jobs/resque.html.erb +1 -0
  16. data/app/views/qujo/jobs/show.html.erb +46 -0
  17. data/config/routes.rb +13 -0
  18. data/lib/qujo.rb +34 -0
  19. data/lib/qujo/concerns/common.rb +117 -0
  20. data/lib/qujo/concerns/exceptions.rb +27 -0
  21. data/lib/qujo/concerns/logging.rb +36 -0
  22. data/lib/qujo/concerns/model.rb +36 -0
  23. data/lib/qujo/concerns/status.rb +27 -0
  24. data/lib/qujo/database/mongoid.rb +25 -0
  25. data/lib/qujo/engine.rb +6 -0
  26. data/lib/qujo/queue/resque.rb +29 -0
  27. data/lib/qujo/queue/resque/job_worker.rb +25 -0
  28. data/lib/qujo/queue/resque/schedule_worker.rb +30 -0
  29. data/lib/qujo/version.rb +9 -0
  30. data/lib/tasks/qujo_tasks.rake +4 -0
  31. data/test/dummy/README.rdoc +261 -0
  32. data/test/dummy/Rakefile +7 -0
  33. data/test/dummy/app/assets/javascripts/application.js +15 -0
  34. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  35. data/test/dummy/app/controllers/application_controller.rb +3 -0
  36. data/test/dummy/app/helpers/application_helper.rb +2 -0
  37. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  38. data/test/dummy/config.ru +4 -0
  39. data/test/dummy/config/application.rb +65 -0
  40. data/test/dummy/config/boot.rb +10 -0
  41. data/test/dummy/config/environment.rb +5 -0
  42. data/test/dummy/config/environments/development.rb +31 -0
  43. data/test/dummy/config/environments/production.rb +64 -0
  44. data/test/dummy/config/environments/test.rb +35 -0
  45. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  46. data/test/dummy/config/initializers/inflections.rb +15 -0
  47. data/test/dummy/config/initializers/mime_types.rb +5 -0
  48. data/test/dummy/config/initializers/secret_token.rb +7 -0
  49. data/test/dummy/config/initializers/session_store.rb +8 -0
  50. data/test/dummy/config/initializers/wrap_parameters.rb +10 -0
  51. data/test/dummy/config/locales/en.yml +5 -0
  52. data/test/dummy/config/routes.rb +4 -0
  53. data/test/dummy/public/404.html +26 -0
  54. data/test/dummy/public/422.html +26 -0
  55. data/test/dummy/public/500.html +25 -0
  56. data/test/dummy/public/favicon.ico +0 -0
  57. data/test/dummy/script/rails +6 -0
  58. data/test/integration/navigation_test.rb +9 -0
  59. data/test/qujo_test.rb +7 -0
  60. data/test/test_helper.rb +15 -0
  61. metadata +189 -0
@@ -0,0 +1,20 @@
1
+ Copyright 2013 YOURNAME
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.
@@ -0,0 +1,3 @@
1
+ = Qujo
2
+
3
+ This project rocks and uses MIT-LICENSE.
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Qujo'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+
25
+
26
+ Bundler::GemHelper.install_tasks
27
+
28
+ require 'rake/testtask'
29
+
30
+ Rake::TestTask.new(:test) do |t|
31
+ t.libs << 'lib'
32
+ t.libs << 'test'
33
+ t.pattern = 'test/**/*_test.rb'
34
+ t.verbose = false
35
+ end
36
+
37
+
38
+ task :default => :test
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
@@ -0,0 +1,124 @@
1
+ var interval = null;
2
+ function updateStatus() {
3
+ console.log("update status");
4
+
5
+ var q = $("#qujo_status").first();
6
+ q.addClass('label-inverse');
7
+ console.log("status: get");
8
+
9
+ $.get("/jobs/status", function (d) {
10
+ console.log("status: return");
11
+ q.removeClass('label-inverse');
12
+ q.removeClass("label-important");
13
+
14
+ var j = $("#jobs_status").first();
15
+ j.removeClass("badge-important");
16
+ j.text(d["jobs"]["count"]);
17
+ if (d["jobs"]["error"]) {
18
+ q.addClass("label label-important");
19
+ j.addClass("badge-important")
20
+ }
21
+
22
+ var r = $("#resque_status").first();
23
+ r.removeClass("badge-important");
24
+ r.text(d["resque"]["count"]);
25
+ if (d["resque"]["error"]) {
26
+ q.addClass("label-important");
27
+ r.addClass("badge-important")
28
+ }
29
+ }).fail(function(d){
30
+ var q = $("#qujo_status").first();
31
+
32
+ var j = $("#jobs_status").first();
33
+ j.addClass("badge-important");
34
+ j.text('?');
35
+
36
+ var r = $("#resque_status").first();
37
+ r.addClass("badge-important");
38
+ r.text('?');
39
+
40
+ q.addClass("label-important");
41
+
42
+ console.log("disable interval");
43
+ clearInterval(interval);
44
+ });
45
+ }
46
+
47
+ $(function () {
48
+ if ($("#jobs_status").size()) {
49
+ interval = setInterval(updateStatus, 2000);
50
+ }
51
+
52
+ $(".create_job").on("click", function () {
53
+ var c = $(this).attr("klass");
54
+ console.log("create job");
55
+ $.post("/jobs", {job: {_type: c}}, function (d) {
56
+ console.log("create job returned")
57
+ });
58
+ });
59
+
60
+ $(document).delegate(".job_cancel", "click", function (e) {
61
+ e.preventDefault();
62
+ var id = $(this).attr("data-id");
63
+ var tr = $(this).parent("td").parent("tr");
64
+ var u = "/jobs/"+id+".json";
65
+ console.log("job_cancel:"+u);
66
+ $.post(u, { _method: "DELETE" }, function(){
67
+ console.log("returned");
68
+ if (tr) {
69
+ // $(tr).fadeOut(500, function(){ $(this).remove();})
70
+ $(tr).addClass("deleting");
71
+ }
72
+ });
73
+ });
74
+
75
+ $(document).delegate(".job_retry", "click", function (e) {
76
+ e.preventDefault();
77
+ var id = $(this).attr("data-id");
78
+ if ($(this).hasClass("disabled")) {
79
+ console.log("job " + id + "clicked, but disabled");
80
+ } else {
81
+ console.log("job " + id + " sending retry");
82
+ $(this).addClass("disabled");
83
+ $.post("/jobs/" + id + "/refresh.json", {}, function () {
84
+ console.log("refresh sent");
85
+ });
86
+ }
87
+ });
88
+
89
+ $(document).delegate(".job_accept", "click", function (e) {
90
+ e.preventDefault();
91
+ var id = $(this).attr("data-id");
92
+ var tp = $(this).attr("data-type");
93
+ var tr = $(this).parent("td").parent("tr");
94
+ if (id != "nil" && tp != "unknown") {
95
+ var u = "/jobs/" + id + "/accept.json";
96
+ console.log("accept_me:" + u);
97
+ $.post(u, {}, function () {
98
+ console.log("returned");
99
+ if (tr) {
100
+ // $(tr).fadeOut(500, function(){ $(this).remove();})
101
+ $(tr).addClass("deleting");
102
+ }
103
+ });
104
+ }
105
+ });
106
+
107
+ $(document).delegate(".job_accept_all", "click", function (e) {
108
+ e.preventDefault();
109
+ var id = $(this).attr("data-id");
110
+ var tp = $(this).attr("data-type");
111
+ var tr = $(this).parent("td").parent("tr");
112
+ if (id != "nil" && tp != "unknown") {
113
+ var u = "/jobs/all/accept.json";
114
+ console.log("accept_me:" + u);
115
+ $.post(u, {}, function () {
116
+ console.log("returned");
117
+ if (tr) {
118
+ // $(tr).fadeOut(500, function(){ $(this).remove();})
119
+ $(tr).addClass("deleting");
120
+ }
121
+ });
122
+ }
123
+ });
124
+ });
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,3 @@
1
+ class Qujo::ApplicationController < ApplicationController
2
+
3
+ end
@@ -0,0 +1,175 @@
1
+ class Qujo::JobsController < ApplicationController
2
+ # GET /jobs
3
+ # GET /jobs.json
4
+ def index
5
+ #@jobs = Job.all
6
+ q = Job.scoped
7
+ q = q.unscoped
8
+ @jobs = q.desc(:created_at).limit(25).all
9
+
10
+ respond_to do |format|
11
+ format.html # index.html.erb
12
+ format.json { render json: @jobs }
13
+ end
14
+ end
15
+
16
+ def resque
17
+
18
+ end
19
+
20
+ def status
21
+ job_count = Job.count
22
+ job_error = Job.errors?
23
+ resque_count = Resque.workers.count
24
+ resque_error = (resque_count == 0 || Resque::Failure.count > 0)
25
+ d = {
26
+ jobs: {
27
+ count: job_count,
28
+ error: job_error
29
+ },
30
+ resque: {
31
+ count: resque_count,
32
+ error: resque_error,
33
+ }
34
+ }
35
+ render json: d, status: :ok
36
+ end
37
+
38
+ # GET /jobs/errors
39
+ # GET /jobs/errors.json
40
+ def errors
41
+ #@jobs = Job.all
42
+ q = Job.scoped
43
+ @jobs = q.errors.desc(:created_at).all
44
+
45
+ respond_to do |format|
46
+ format.html { render "index"} # index.html.erb
47
+ format.json { render json: @jobs }
48
+ end
49
+ end
50
+
51
+ # GET /jobs/all
52
+ # GET /jobs/all.json
53
+ def all
54
+ #@jobs = Job.all
55
+ q = Job.scoped
56
+ q = q.unscoped
57
+ @jobs = q.desc(:created_at).limit(50).all
58
+
59
+ respond_to do |format|
60
+ format.html { render "index"} # index.html.erb
61
+ format.json { render json: @jobs }
62
+ end
63
+ end
64
+
65
+ # GET /jobs/1
66
+ # GET /jobs/1.json
67
+ def show
68
+ @job = Job.unscoped.find(params[:id])
69
+ # sometimes things don't get updated (can't see trace on errors)
70
+ # if identity map is enabled
71
+ @job = @job.reload
72
+
73
+ respond_to do |format|
74
+ format.html # show.html.erb
75
+ format.json { render json: @job }
76
+ end
77
+ end
78
+
79
+ # GET /jobs/new
80
+ # GET /jobs/new.json
81
+ def new
82
+ @job = Job.new
83
+
84
+ respond_to do |format|
85
+ format.html # new.html.erb
86
+ format.json { render json: @job }
87
+ end
88
+ end
89
+
90
+ ## GET /jobs/1/edit
91
+ #def edit
92
+ # @job = Job.find(params[:id])
93
+ #end
94
+
95
+ # POST /jobs
96
+ # POST /jobs.json
97
+ def create
98
+ p = params[:job]
99
+ logger.info "JOB CREATE: #{p.inspect}"
100
+ k = Job
101
+ if p["_type"]
102
+ t = p.delete("_type")
103
+ begin
104
+ k = t.constantize
105
+ rescue => e
106
+ logger.info "TYPE:#{k} failed"
107
+ end
108
+ end
109
+ logger.info "JOB CREATE: #{p.inspect}"
110
+ @job = k.new(p)
111
+
112
+ respond_to do |format|
113
+ if @job.save
114
+ @job.enqueue
115
+ format.html { redirect_to @job, notice: 'Job was successfully created.' }
116
+ format.json { render json: @job, status: :created, location: @job }
117
+ else
118
+ format.html { render action: "new" }
119
+ format.json { render json: @job.errors, status: :unprocessable_entity }
120
+ end
121
+ end
122
+ end
123
+
124
+ ## PUT /jobs/1
125
+ ## PUT /jobs/1.json
126
+ #def update
127
+ # @job = Job.find(params[:id])
128
+ #
129
+ # respond_to do |format|
130
+ # if @job.update_attributes(params[:job])
131
+ # format.html { redirect_to @job, notice: 'Job was successfully updated.' }
132
+ # format.json { head :no_content }
133
+ # else
134
+ # format.html { render action: "edit" }
135
+ # format.json { render json: @job.errors, status: :unprocessable_entity }
136
+ # end
137
+ # end
138
+ #end
139
+
140
+ def refresh
141
+ @job = Job.unscoped.find(params[:id])
142
+ @job.retry
143
+ @job.enqueue
144
+
145
+ head :no_content
146
+ rescue => e
147
+ render json: {message: e.message}
148
+ end
149
+
150
+ def accept
151
+ id = params[:id]
152
+ if id == "all"
153
+ Job.where(accepted_at: nil).update_all(accepted_at: Time.now)
154
+ else
155
+ @job = Job.find(id)
156
+ @job.accept
157
+ end
158
+
159
+ head :no_content
160
+ rescue => e
161
+ render json: {message: e.message}
162
+ end
163
+
164
+ # DELETE /jobs/1
165
+ # DELETE /jobs/1.json
166
+ def destroy
167
+ @job = Job.unscoped.find(params[:id])
168
+ @job.cancel
169
+
170
+ respond_to do |format|
171
+ format.html { redirect_to jobs_url }
172
+ format.json { head :no_content }
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,4 @@
1
+ module Qujo
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,29 @@
1
+ <a href="#" id="qujo" class="dropdown-toggle" data-toggle="dropdown">
2
+ <span id="qujo_status" class="label">Qujo</span>
3
+ <b class="caret"></b>
4
+ </a>
5
+ <ul class="dropdown-menu">
6
+ <li>
7
+ <%= link_to qujo.jobs_path, title: "manage jobs" do %>
8
+ <span id="jobs_status" title="active jobs" class="badge">?</span> Manage Jobs
9
+ <% end %>
10
+ </li>
11
+ <li>
12
+ <%= link_to qujo.resque_jobs_path, title: "manage resque" do %>
13
+ <span id="resque_status" title="resque workers" class="badge">?</span> Manage Resque
14
+ <% end %>
15
+ </li>
16
+ <% if defined?(jobs) %>
17
+ <li class="divider"></li>
18
+ <% jobs.each do |k, v| %>
19
+ <li class='nav-header'><%= k %></li>
20
+ <% v.each do |l| %>
21
+ <li>
22
+ <%= link_to "#", class: "create_job", klass: l do %>
23
+ Run <%= l %>
24
+ <% end %>
25
+ </li>
26
+ <% end %>
27
+ <% end %>
28
+ <% end %>
29
+ </ul>
@@ -0,0 +1,14 @@
1
+ <%= simple_form_for(@job) do |f| %>
2
+ <%= f.error_notification %>
3
+
4
+ <div class="form-inputs">
5
+ <%= f.input :id, disabled: true %>
6
+ <%= f.input :status, collection: Job.get_status_values %>
7
+ <%= f.input :data, disabled: true %>
8
+ <%= f.input :message, disabled: true %>
9
+ </div>
10
+
11
+ <div class="form-actions">
12
+ <%= f.button :submit %>
13
+ </div>
14
+ <% end %>