rocketjob_mission_control 1.2.4 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +201 -0
- data/README.md +85 -0
- data/Rakefile +12 -18
- data/app/assets/javascripts/rocket_job_mission_control/application.js +3 -0
- data/app/assets/javascripts/rocket_job_mission_control/base.js.coffee +9 -12
- data/app/assets/javascripts/rocket_job_mission_control/datatable.js.coffee +31 -0
- data/app/assets/javascripts/rocket_job_mission_control/dirmon_entries.js.coffee +0 -1
- data/app/assets/stylesheets/rocket_job_mission_control/application.scss +2 -0
- data/app/assets/stylesheets/rocket_job_mission_control/base.scss +310 -357
- data/app/assets/stylesheets/rocket_job_mission_control/bootstrap_and_overrides.scss +474 -3
- data/app/assets/stylesheets/rocket_job_mission_control/callout.scss +57 -12
- data/app/assets/stylesheets/rocket_job_mission_control/jobs.scss +3 -2
- data/app/assets/stylesheets/rocket_job_mission_control/worker_processes.scss +9 -0
- data/app/controllers/rocket_job_mission_control/active_processes_controller.rb +26 -0
- data/app/controllers/rocket_job_mission_control/dirmon_entries/index_filters_controller.rb +50 -0
- data/app/controllers/rocket_job_mission_control/dirmon_entries_controller.rb +11 -14
- data/app/controllers/rocket_job_mission_control/jobs/failures_controller.rb +2 -2
- data/app/controllers/rocket_job_mission_control/jobs/index_filters_controller.rb +69 -0
- data/app/controllers/rocket_job_mission_control/jobs_controller.rb +10 -12
- data/app/controllers/rocket_job_mission_control/workers/index_filters_controller.rb +50 -0
- data/app/controllers/rocket_job_mission_control/workers_controller.rb +14 -5
- data/app/datatables/rocket_job_mission_control/active_processes_datatable.rb +79 -0
- data/app/datatables/rocket_job_mission_control/completed_jobs_datatable.rb +26 -0
- data/app/datatables/rocket_job_mission_control/dirmon_entries_datatable.rb +95 -0
- data/app/datatables/rocket_job_mission_control/interrupted_jobs_datatable.rb +25 -0
- data/app/datatables/rocket_job_mission_control/jobs_datatable.rb +95 -0
- data/app/datatables/rocket_job_mission_control/queued_jobs_datatable.rb +22 -0
- data/app/datatables/rocket_job_mission_control/running_jobs_datatable.rb +35 -0
- data/app/datatables/rocket_job_mission_control/scheduled_jobs_datatable.rb +30 -0
- data/app/datatables/rocket_job_mission_control/workers_datatable.rb +127 -0
- data/app/helpers/rocket_job_mission_control/application_helper.rb +21 -2
- data/app/helpers/rocket_job_mission_control/dirmon_entries_helper.rb +7 -0
- data/app/helpers/rocket_job_mission_control/jobs_helper.rb +9 -26
- data/app/helpers/rocket_job_mission_control/workers_helper.rb +18 -6
- data/app/interactors/rocket_job_mission_control/dirmon_entries/search.rb +19 -0
- data/app/interactors/rocket_job_mission_control/jobs/search.rb +19 -0
- data/app/interactors/rocket_job_mission_control/workers/search.rb +19 -0
- data/app/models/job_failures.rb +5 -5
- data/app/views/layouts/rocket_job_mission_control/application.html.haml +22 -22
- data/app/views/layouts/rocket_job_mission_control/partials/_header.html.haml +33 -18
- data/app/views/layouts/rocket_job_mission_control/partials/_sidebar.html.haml +11 -24
- data/app/views/rocket_job_mission_control/active_processes/index.html.haml +24 -0
- data/app/views/rocket_job_mission_control/dirmon_entries/_form.html.haml +11 -10
- data/app/views/rocket_job_mission_control/dirmon_entries/_properties.html.haml +6 -3
- data/app/views/rocket_job_mission_control/dirmon_entries/_sidebar.html.haml +27 -0
- data/app/views/rocket_job_mission_control/dirmon_entries/_status.html.haml +0 -3
- data/app/views/rocket_job_mission_control/dirmon_entries/edit.html.haml +3 -7
- data/app/views/rocket_job_mission_control/dirmon_entries/index.html.haml +17 -10
- data/app/views/rocket_job_mission_control/dirmon_entries/index_filters/disabled.html.haml +17 -0
- data/app/views/rocket_job_mission_control/dirmon_entries/index_filters/enabled.html.haml +17 -0
- data/app/views/rocket_job_mission_control/dirmon_entries/index_filters/failed.html.haml +17 -0
- data/app/views/rocket_job_mission_control/dirmon_entries/index_filters/pending.html.haml +17 -0
- data/app/views/rocket_job_mission_control/dirmon_entries/new.html.haml +5 -8
- data/app/views/rocket_job_mission_control/dirmon_entries/show.html.haml +18 -22
- data/app/views/rocket_job_mission_control/jobs/_sidebar.html.haml +28 -0
- data/app/views/rocket_job_mission_control/jobs/failures/index.html.haml +2 -2
- data/app/views/rocket_job_mission_control/jobs/index.html.haml +23 -10
- data/app/views/rocket_job_mission_control/jobs/index_filters/aborted.html.haml +22 -0
- data/app/views/rocket_job_mission_control/jobs/index_filters/completed.html.haml +23 -0
- data/app/views/rocket_job_mission_control/jobs/index_filters/failed.html.haml +22 -0
- data/app/views/rocket_job_mission_control/jobs/index_filters/paused.html.haml +22 -0
- data/app/views/rocket_job_mission_control/jobs/index_filters/queued.html.haml +23 -0
- data/app/views/rocket_job_mission_control/jobs/index_filters/running.html.haml +24 -0
- data/app/views/rocket_job_mission_control/jobs/index_filters/scheduled.html.haml +23 -0
- data/app/views/rocket_job_mission_control/jobs/show.html.haml +5 -8
- data/app/views/rocket_job_mission_control/workers/_sidebar.html.haml +20 -0
- data/app/views/rocket_job_mission_control/workers/index.html.haml +36 -59
- data/app/views/rocket_job_mission_control/workers/index_filters/paused.html.haml +37 -0
- data/app/views/rocket_job_mission_control/workers/index_filters/running.html.haml +37 -0
- data/app/views/rocket_job_mission_control/workers/index_filters/starting.html.haml +37 -0
- data/app/views/rocket_job_mission_control/workers/index_filters/stopping.html.haml +37 -0
- data/config/routes.rb +28 -5
- data/lib/rocket_job_mission_control/engine.rb +2 -0
- data/lib/rocket_job_mission_control/version.rb +1 -1
- data/spec/controllers/application_controller_spec.rb +1 -1
- data/spec/controllers/dirmon_entries_controller_spec.rb +35 -97
- data/spec/controllers/jobs/failures_controller_spec.rb +4 -4
- data/spec/controllers/jobs_controller_spec.rb +10 -80
- data/spec/dummy/config/environments/development.rb +7 -7
- data/spec/dummy/config/environments/test.rb +9 -9
- data/spec/dummy/log/test.log +5446 -23487
- data/spec/helpers/application_helper_spec.rb +58 -0
- data/spec/helpers/jobs_helper_spec.rb +0 -65
- data/spec/helpers/slices_helper_spec.rb +1 -1
- data/spec/helpers/workers_helper_spec.rb +1 -1
- metadata +64 -44
- data/MIT-LICENSE +0 -20
- data/app/assets/javascripts/rocket_job_mission_control/jobs.js.coffee +0 -11
- data/app/views/rocket_job_mission_control/dirmon_entries/_list.html.haml +0 -31
- data/app/views/rocket_job_mission_control/jobs/_list.html.haml +0 -35
- data/app/views/rocket_job_mission_control/jobs/running.html.haml +0 -37
- data/spec/dummy/log/development.log +0 -0
- data/spec/views/workers/index.html.haml_spec.rb +0 -23
@@ -0,0 +1,35 @@
|
|
1
|
+
module RocketJobMissionControl
|
2
|
+
class RunningJobsDatatable < JobsDatatable
|
3
|
+
private
|
4
|
+
|
5
|
+
def data
|
6
|
+
jobs.map do |job|
|
7
|
+
{
|
8
|
+
'0' => class_with_link(job),
|
9
|
+
'1' => h(job.description.try(:truncate, 50)),
|
10
|
+
'2' => progress(job),
|
11
|
+
'3' => h(job.priority),
|
12
|
+
'4' => h(started(job)),
|
13
|
+
'DT_RowClass' => "card callout callout-#{job.state}"
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def sort_column(index)
|
19
|
+
columns = %w[_type description percent_complete priority started_at]
|
20
|
+
columns[index.to_i]
|
21
|
+
end
|
22
|
+
|
23
|
+
def progress(job)
|
24
|
+
<<-EOS
|
25
|
+
<div class='progress'>
|
26
|
+
<div class='progress-bar' style="width: #{job.percent_complete}%;", title="#{job.percent_complete}% complete."></div>
|
27
|
+
</div>
|
28
|
+
EOS
|
29
|
+
end
|
30
|
+
|
31
|
+
def started(job)
|
32
|
+
"#{RocketJob.seconds_as_duration(Time.now - job.started_at)} ago" if job.started_at
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module RocketJobMissionControl
|
2
|
+
class ScheduledJobsDatatable < JobsDatatable
|
3
|
+
private
|
4
|
+
|
5
|
+
def data
|
6
|
+
jobs.map do |job|
|
7
|
+
{
|
8
|
+
'0' => class_with_link(job),
|
9
|
+
'1' => h(job.description.try(:truncate, 50)),
|
10
|
+
'2' => h(time_till_run(job)),
|
11
|
+
'3' => h(cron_schedule(job)),
|
12
|
+
'DT_RowClass' => "card callout callout-#{job.state}"
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def sort_column(index)
|
18
|
+
columns = %w[_type description run_at cron_schedule]
|
19
|
+
columns[index.to_i]
|
20
|
+
end
|
21
|
+
|
22
|
+
def time_till_run(job)
|
23
|
+
RocketJob.seconds_as_duration(job.run_at - Time.now)
|
24
|
+
end
|
25
|
+
|
26
|
+
def cron_schedule(job)
|
27
|
+
job.cron_schedule if job.respond_to?(:cron_schedule)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module RocketJobMissionControl
|
2
|
+
class WorkersDatatable
|
3
|
+
delegate :params,
|
4
|
+
:link_to,
|
5
|
+
:worker_icon,
|
6
|
+
:worker_path,
|
7
|
+
:stop_worker_path,
|
8
|
+
:resume_worker_path,
|
9
|
+
:pause_worker_path,
|
10
|
+
:worker_card_class,
|
11
|
+
:render, to: :@view
|
12
|
+
|
13
|
+
delegate :h, to: 'ERB::Util'
|
14
|
+
|
15
|
+
def initialize(view, workers)
|
16
|
+
@view = view
|
17
|
+
@unfiltered_workers = workers
|
18
|
+
end
|
19
|
+
|
20
|
+
def as_json(options = {})
|
21
|
+
{
|
22
|
+
:draw => params[:draw].to_i,
|
23
|
+
:recordsTotal => get_raw_records.count,
|
24
|
+
:recordsFiltered => filter_records(get_raw_records).count,
|
25
|
+
:data => data
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def data
|
32
|
+
workers.map do |worker|
|
33
|
+
{
|
34
|
+
'0' => name_with_icon(worker),
|
35
|
+
'1' => h(threads(worker)),
|
36
|
+
'2' => h(started_ago(worker)),
|
37
|
+
'3' => h(time_since_heartbeat(worker)),
|
38
|
+
'4' => action_links_html(worker),
|
39
|
+
'DT_RowClass' => "card callout #{worker_card_class(worker)}"
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_raw_records
|
45
|
+
@unfiltered_workers
|
46
|
+
end
|
47
|
+
|
48
|
+
def workers
|
49
|
+
@workers ||= fetch_workers
|
50
|
+
end
|
51
|
+
|
52
|
+
def fetch_workers
|
53
|
+
records = get_raw_records
|
54
|
+
records = sort_records(records) if params[:order].present?
|
55
|
+
records = filter_records(records) if params[:search].present?
|
56
|
+
records = paginate_records(records) unless params[:length].present? && params[:length] == '-1'
|
57
|
+
records
|
58
|
+
end
|
59
|
+
|
60
|
+
def page
|
61
|
+
(params[:start].to_i / per_page) + 1
|
62
|
+
end
|
63
|
+
|
64
|
+
def per_page
|
65
|
+
params.fetch(:length, 10).to_i
|
66
|
+
end
|
67
|
+
|
68
|
+
def sort_records(records)
|
69
|
+
sort_by = {}
|
70
|
+
params[:order].keys.each do |key|
|
71
|
+
sort_by[sort_column(params[:order][key][:column])] = params[:order][key][:dir]
|
72
|
+
end
|
73
|
+
records.sort(sort_by)
|
74
|
+
end
|
75
|
+
|
76
|
+
def sort_column(index)
|
77
|
+
columns = %w[name max_threads started_at heartbeat.updated_at]
|
78
|
+
columns[index.to_i]
|
79
|
+
end
|
80
|
+
|
81
|
+
def filter_records(records)
|
82
|
+
return records unless (params[:search].present? && params[:search][:value].present?)
|
83
|
+
conditions = params[:search][:value]#build_conditions_for(params[:search][:value])
|
84
|
+
records = RocketJobMissionControl::Workers::Search.new(conditions, records).execute if conditions
|
85
|
+
records
|
86
|
+
end
|
87
|
+
|
88
|
+
def paginate_records(records)
|
89
|
+
Kaminari.paginate_array(records.all).page(page).per(per_page)
|
90
|
+
end
|
91
|
+
|
92
|
+
def name_with_icon(worker)
|
93
|
+
<<-EOS
|
94
|
+
<i class="fa #{worker_icon(worker)}" style="font-size: 75%" title="#{worker.state}"></i>
|
95
|
+
#{worker.name}
|
96
|
+
EOS
|
97
|
+
end
|
98
|
+
|
99
|
+
def threads(worker)
|
100
|
+
"#{worker.heartbeat.current_threads.to_i}/#{worker.max_threads}"
|
101
|
+
end
|
102
|
+
|
103
|
+
def started_ago(worker)
|
104
|
+
"#{RocketJob.seconds_as_duration(Time.now - worker.started_at)} ago"
|
105
|
+
end
|
106
|
+
|
107
|
+
def time_since_heartbeat(worker)
|
108
|
+
"#{RocketJob.seconds_as_duration(Time.now - worker.heartbeat.updated_at)} ago"
|
109
|
+
end
|
110
|
+
|
111
|
+
def action_links_html(worker)
|
112
|
+
actions = '<div class="actions">'
|
113
|
+
if worker.stopping?
|
114
|
+
actions += "Worker is stopping..."
|
115
|
+
actions += "#{ link_to "destroy", worker_path(worker), method: :delete, class: 'btn btn-danger', data: { confirm: "Destroy this worker?"} }"
|
116
|
+
else
|
117
|
+
if worker.paused?
|
118
|
+
actions += "#{ link_to "resume", resume_worker_path(worker), method: :patch, class: 'btn btn-default', data: { confirm: "Resume this worker?"} }"
|
119
|
+
else
|
120
|
+
actions += "#{ link_to "pause", pause_worker_path(worker), method: :patch, class: 'btn btn-default', data: { confirm: "Pause this worker?"} }"
|
121
|
+
end
|
122
|
+
actions += "#{ link_to "stop", stop_worker_path(worker), method: :patch, class: 'btn btn-danger', data: { confirm: "Stop this worker?"} }"
|
123
|
+
end
|
124
|
+
actions += '</div>'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -1,5 +1,25 @@
|
|
1
1
|
module RocketJobMissionControl
|
2
2
|
module ApplicationHelper
|
3
|
+
STATE_ICON_MAP = {
|
4
|
+
aborted: 'fa-stop',
|
5
|
+
completed: 'fa-check',
|
6
|
+
disabled: 'fa-stop',
|
7
|
+
enabled: 'fa-check',
|
8
|
+
failed: 'fa-exclamation-triangle',
|
9
|
+
paused: 'fa-pause',
|
10
|
+
pending: 'fa-inbox',
|
11
|
+
queued: 'fa-inbox',
|
12
|
+
running: 'fa-play',
|
13
|
+
scheduled: 'fa-clock-o',
|
14
|
+
starting: 'fa-cogs',
|
15
|
+
stopping: 'fa-stop',
|
16
|
+
zombie: 'fa-hourglass-o'
|
17
|
+
}
|
18
|
+
|
19
|
+
def state_icon(state)
|
20
|
+
STATE_ICON_MAP[state.to_sym] + ' ' + state.to_s
|
21
|
+
end
|
22
|
+
|
3
23
|
def site_title
|
4
24
|
'Rocket Job Mission Control'
|
5
25
|
end
|
@@ -15,9 +35,8 @@ module RocketJobMissionControl
|
|
15
35
|
|
16
36
|
def pretty_print_array_or_hash(arguments)
|
17
37
|
return arguments unless arguments.kind_of?(Array) || arguments.kind_of?(Hash)
|
18
|
-
json_string_options = {
|
38
|
+
json_string_options = {space: ' ', indent: ' ', array_nl: '<br />', object_nl: '<br />'}
|
19
39
|
JSON.generate(arguments, json_string_options).html_safe
|
20
40
|
end
|
21
|
-
|
22
41
|
end
|
23
42
|
end
|
@@ -1,31 +1,18 @@
|
|
1
1
|
module RocketJobMissionControl
|
2
2
|
module JobsHelper
|
3
|
-
STATE_ICON_MAP = {
|
4
|
-
aborted: 'fa-stop',
|
5
|
-
completed: 'fa-check',
|
6
|
-
disabled: 'fa-stop',
|
7
|
-
enabled: 'fa-check',
|
8
|
-
failed: 'fa-exclamation-triangle',
|
9
|
-
paused: 'fa-pause',
|
10
|
-
pending: 'fa-inbox',
|
11
|
-
queued: 'fa-inbox',
|
12
|
-
running: 'fa-play',
|
13
|
-
scheduled: 'fa-clock-o',
|
14
|
-
}
|
15
|
-
|
16
|
-
def job_state_icon(state)
|
17
|
-
STATE_ICON_MAP[state.to_sym] + ' ' + state.to_s
|
18
|
-
end
|
19
|
-
|
20
3
|
def job_icon(job)
|
21
|
-
# TODO move this logic to RocketJob::Job
|
22
4
|
state =
|
23
|
-
if job.
|
5
|
+
if job.scheduled?
|
24
6
|
:scheduled
|
25
7
|
else
|
26
8
|
job.state
|
27
9
|
end
|
28
|
-
|
10
|
+
state_icon(state)
|
11
|
+
end
|
12
|
+
|
13
|
+
def job_counts_by_state(state)
|
14
|
+
state = 'queued_now' if state == 'queued'
|
15
|
+
RocketJob::Job.counts_by_state.fetch(state.downcase.to_sym, 0)
|
29
16
|
end
|
30
17
|
|
31
18
|
def job_action_link(action, path, http_method=:get)
|
@@ -33,8 +20,8 @@ module RocketJobMissionControl
|
|
33
20
|
action,
|
34
21
|
path,
|
35
22
|
method: http_method,
|
36
|
-
class:
|
37
|
-
data:
|
23
|
+
class: 'btn btn-default',
|
24
|
+
data: {confirm: t(:confirm, scope: [:job, :action], action: action)}
|
38
25
|
)
|
39
26
|
end
|
40
27
|
|
@@ -50,9 +37,5 @@ module RocketJobMissionControl
|
|
50
37
|
end
|
51
38
|
end
|
52
39
|
|
53
|
-
def job_title(job)
|
54
|
-
perform_method = job.perform_method == :perform ? '' : "##{job.perform_method}"
|
55
|
-
"#{job.class.name}#{perform_method}"
|
56
|
-
end
|
57
40
|
end
|
58
41
|
end
|
@@ -1,18 +1,30 @@
|
|
1
1
|
module RocketJobMissionControl
|
2
2
|
module WorkersHelper
|
3
|
+
def worker_counts_by_state(state)
|
4
|
+
RocketJob::Worker.counts_by_state.fetch(state.downcase.to_sym, 0)
|
5
|
+
end
|
6
|
+
|
7
|
+
def worker_icon(worker)
|
8
|
+
state =
|
9
|
+
if worker.zombie?
|
10
|
+
'zombie'
|
11
|
+
else
|
12
|
+
worker.state
|
13
|
+
end
|
14
|
+
state_icon(state)
|
15
|
+
end
|
3
16
|
|
4
17
|
def worker_card_class(worker)
|
5
18
|
if worker.zombie?
|
6
|
-
'callout-zombie
|
19
|
+
'callout-zombie'
|
7
20
|
else
|
8
21
|
map = {
|
9
|
-
running: 'callout-success
|
10
|
-
paused: 'callout-warning
|
11
|
-
stopping: 'callout-alert
|
22
|
+
running: 'callout-success',
|
23
|
+
paused: 'callout-warning',
|
24
|
+
stopping: 'callout-alert',
|
12
25
|
}
|
13
|
-
map[worker.state] || 'callout-info
|
26
|
+
map[worker.state] || 'callout-info'
|
14
27
|
end
|
15
28
|
end
|
16
|
-
|
17
29
|
end
|
18
30
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RocketJobMissionControl
|
2
|
+
module DirmonEntries
|
3
|
+
class Search
|
4
|
+
attr_reader :results, :search_term
|
5
|
+
|
6
|
+
def initialize(search_term, search_subset)
|
7
|
+
@search_term = search_term
|
8
|
+
@results = search_subset
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute
|
12
|
+
if !search_term.blank?
|
13
|
+
@results = @results.where('$or' => [{job_class_name: /#{search_term}/i}, {name: /#{search_term}/i}, {pattern: /#{search_term}/i}])
|
14
|
+
end
|
15
|
+
@results
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RocketJobMissionControl
|
2
|
+
module Jobs
|
3
|
+
class Search
|
4
|
+
attr_reader :results, :search_term
|
5
|
+
|
6
|
+
def initialize(search_term, search_subset)
|
7
|
+
@search_term = search_term
|
8
|
+
@results = search_subset
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute
|
12
|
+
if !search_term.blank?
|
13
|
+
@results = @results.where('$or' => [{_type: /#{search_term}/i}, {description: /#{search_term}/i}])
|
14
|
+
end
|
15
|
+
@results
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RocketJobMissionControl
|
2
|
+
module Workers
|
3
|
+
class Search
|
4
|
+
attr_reader :results, :search_term
|
5
|
+
|
6
|
+
def initialize(search_term, search_subset)
|
7
|
+
@search_term = search_term
|
8
|
+
@results = search_subset
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute
|
12
|
+
if !search_term.blank?
|
13
|
+
@results = @results.where('$or' => [{name: /#{search_term}/i}])
|
14
|
+
end
|
15
|
+
@results
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/app/models/job_failures.rb
CHANGED
@@ -13,13 +13,13 @@ class JobFailures
|
|
13
13
|
@slice_errors ||= job.input.collection.aggregate(
|
14
14
|
[
|
15
15
|
{
|
16
|
-
'$match' => {
|
16
|
+
'$match' => {state: 'failed'}
|
17
17
|
},
|
18
18
|
{
|
19
19
|
'$group' => {
|
20
|
-
_id: {
|
21
|
-
messages: {
|
22
|
-
count: {
|
20
|
+
_id: {error_class: '$exception.class_name'},
|
21
|
+
messages: {'$addToSet' => '$exception.message'},
|
22
|
+
count: {'$sum' => 1}
|
23
23
|
},
|
24
24
|
}
|
25
25
|
]
|
@@ -27,7 +27,7 @@ class JobFailures
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def for_error(error_type, page_offset=0)
|
30
|
-
query
|
30
|
+
query = {'state' => 'failed', 'exception.class_name' => error_type}
|
31
31
|
@job.input.collection.find(query).limit(1).skip(page_offset)
|
32
32
|
end
|
33
33
|
end
|
@@ -21,25 +21,25 @@
|
|
21
21
|
%link{href: "//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css", rel: "stylesheet"}/
|
22
22
|
|
23
23
|
%body.rocket_job
|
24
|
-
#wrapper
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
-
|
33
|
-
.
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
- msg.
|
39
|
-
%
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
24
|
+
#wrapper
|
25
|
+
.container-fluid
|
26
|
+
.row.row-offcanvas.row-offcanvas-left
|
27
|
+
= render partial: 'layouts/rocket_job_mission_control/partials/sidebar'
|
28
|
+
|
29
|
+
.col-sm-10.col-xs-11.white-background#main
|
30
|
+
= render partial: 'layouts/rocket_job_mission_control/partials/header'
|
31
|
+
|
32
|
+
.flash.text-center
|
33
|
+
- flash.each do |key, msg|
|
34
|
+
- if msg
|
35
|
+
.alert{class: "alert-#{key} alert-dismissable", role: 'alert'}
|
36
|
+
%button.close{ data: { dismiss: 'alert' } }
|
37
|
+
%span ×
|
38
|
+
-if msg.kind_of? Array
|
39
|
+
%ul.list-unstyled.margin-bottom-0
|
40
|
+
- msg.each do |m|
|
41
|
+
%li= m.html_safe
|
42
|
+
- else
|
43
|
+
= msg.html_safe
|
44
|
+
#content
|
45
|
+
= yield
|
@@ -1,18 +1,33 @@
|
|
1
|
-
#header
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
1
|
+
%nav.navbar.navbar-default#header
|
2
|
+
.container-fluid
|
3
|
+
.navbar-header
|
4
|
+
%button.navbar-toggle.collapsed{ "aria-expanded" => "false", "data-target" => ".navbar-collapse", "data-toggle" => "collapse", :type => "button" }
|
5
|
+
%span.sr-only Toggle navigation
|
6
|
+
%span.icon-bar
|
7
|
+
%span.icon-bar
|
8
|
+
%span.icon-bar
|
9
|
+
%a.navbar-brand.brand{ href: 'http://rocketjob.io', target: '_blank'}
|
10
|
+
= image_tag('rocket_job_mission_control/rocket-icon-64x64.png', size: '32x32')
|
11
|
+
Rocket
|
12
|
+
%span Job
|
13
|
+
.navbar-collapse.collapse
|
14
|
+
%ul.nav.navbar-nav
|
15
|
+
%li
|
16
|
+
= link_to running_jobs_path, class: active_page(running_jobs_path) do
|
17
|
+
%i.fa.fa-home
|
18
|
+
Jobs
|
19
|
+
%li
|
20
|
+
= link_to workers_path, class: active_page(workers_path) do
|
21
|
+
%i.fa.fa-database
|
22
|
+
Workers
|
23
|
+
%li
|
24
|
+
= link_to active_processes_path, class: active_page(active_processes_path) do
|
25
|
+
%i.fa.fa-circle-o-notch
|
26
|
+
Activity
|
27
|
+
%li
|
28
|
+
= link_to enabled_dirmon_entries_path, class: active_page(enabled_dirmon_entries_path) do
|
29
|
+
%i.fa.fa-folder-o
|
30
|
+
Directory Monitors
|
31
|
+
%ul.nav.navbar-nav.navbar-right
|
32
|
+
%li
|
33
|
+
%a{:href => main_app.root_path } Home
|
@@ -1,24 +1,11 @@
|
|
1
|
-
#sidebar-
|
2
|
-
%ul.
|
3
|
-
%li
|
4
|
-
%a
|
5
|
-
%i.fa.fa-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
Jobs
|
13
|
-
%li
|
14
|
-
= link_to workers_path, class: active_page(workers_path) do
|
15
|
-
%i.fa.fa-database
|
16
|
-
Workers
|
17
|
-
%li
|
18
|
-
= link_to running_jobs_path, class: active_page(running_jobs_path) do
|
19
|
-
%i.fa.fa-circle-o-notch
|
20
|
-
Running
|
21
|
-
%li
|
22
|
-
= link_to dirmon_entries_path, class: active_page(dirmon_entries_path) do
|
23
|
-
%i.fa.fa-folder-o
|
24
|
-
Dirmon
|
1
|
+
#sidebar.col-sm-2.col-xs-1.sidebar-offcanvas
|
2
|
+
%ul.nav
|
3
|
+
%li
|
4
|
+
%a.visible-xs{"data-toggle" => "offcanvas", :href => "#"}
|
5
|
+
%i.fa.fa-chevron-right
|
6
|
+
- if @jobs_sidebar
|
7
|
+
= render partial: 'rocket_job_mission_control/jobs/sidebar'
|
8
|
+
- if @dirmon_sidebar
|
9
|
+
= render partial: 'rocket_job_mission_control/dirmon_entries/sidebar'
|
10
|
+
- if @workers_sidebar
|
11
|
+
= render partial: 'rocket_job_mission_control/workers/sidebar'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
.job-list
|
2
|
+
.list
|
3
|
+
.row
|
4
|
+
.col-sm-10
|
5
|
+
%h2 Active Processes
|
6
|
+
.col-sm-2
|
7
|
+
.btn.btn-default.pull-right.dt-reload{ data: { behavior: 'reload' } }
|
8
|
+
%i.fa.fa-refresh
|
9
|
+
%table.table.datatable.active-processes-datatable{ style: "width: 100%", data: { source: "#{active_processes_url(format: 'json')}", column_num: 4 } }
|
10
|
+
%thead
|
11
|
+
%tr
|
12
|
+
%th Hostname : PID
|
13
|
+
%th Class
|
14
|
+
%th Description
|
15
|
+
%th Started
|
16
|
+
%tbody
|
17
|
+
|
18
|
+
:javascript
|
19
|
+
jQuery(function() {
|
20
|
+
new RjmcDatatable(
|
21
|
+
$('.active-processes-datatable'),
|
22
|
+
[{data: '0'}, {data: '1'}, {data: '2'}, {data: '3'}],
|
23
|
+
{ordering: false, searching: false});
|
24
|
+
});
|
@@ -5,19 +5,20 @@
|
|
5
5
|
- @dirmon_entry.errors.messages.each_pair do |field, message|
|
6
6
|
.message
|
7
7
|
= "#{field}: #{message}"
|
8
|
+
|
8
9
|
= form_for @dirmon_entry, url: {action: action} do |f|
|
9
|
-
.
|
10
|
-
|
11
|
-
|
10
|
+
.row
|
11
|
+
.col-md-6
|
12
|
+
.name.form-group
|
13
|
+
= f.label :name
|
14
|
+
= f.text_field :name, class: 'form-control'
|
15
|
+
.col-md-6
|
16
|
+
.job.form-group
|
17
|
+
= f.label :job_class_name
|
18
|
+
= f.text_field :job_class_name, class: 'form-control', disabled: action != :create
|
12
19
|
.path.form-group
|
13
20
|
= f.label :pattern
|
14
21
|
= f.text_field :pattern, class: 'form-control'
|
15
|
-
.job.form-group
|
16
|
-
= f.label :job_class_name
|
17
|
-
= f.text_field :job_class_name, class: 'form-control', disabled: action != :create
|
18
|
-
.job.form-group
|
19
|
-
= f.label :perform_method
|
20
|
-
= f.text_field :perform_method, class: 'form-control', disabled: action != :create
|
21
22
|
.path.form-group
|
22
23
|
= f.label :archive_directory
|
23
24
|
= f.text_field :archive_directory, class: 'form-control'
|
@@ -25,7 +26,7 @@
|
|
25
26
|
.col-md-12
|
26
27
|
= render partial: 'properties', locals: { f: f }
|
27
28
|
|
28
|
-
.buttons
|
29
|
+
.buttons.pull-right
|
29
30
|
= f.submit action, class: 'btn btn-primary'
|
30
31
|
= link_to 'cancel', :back, class: 'btn btn-default'
|
31
32
|
- if action == :create
|
@@ -1,7 +1,7 @@
|
|
1
1
|
- if @dirmon_entry.job_class
|
2
2
|
.arguments
|
3
3
|
.job_arguments.form-group
|
4
|
-
- count = @dirmon_entry.job_class.
|
4
|
+
- count = @dirmon_entry.job_class.rocket_job_argument_count
|
5
5
|
- count.times do |counter|
|
6
6
|
- argument = @dirmon_entry.arguments[counter]
|
7
7
|
= f.label "Argument #{counter + 1}:"
|
@@ -13,15 +13,18 @@
|
|
13
13
|
class: 'form-control'
|
14
14
|
= f.fields_for :properties do |properties|
|
15
15
|
- @dirmon_entry.job_class.rocket_job_properties.each do |property_name|
|
16
|
-
- next if
|
16
|
+
- next if property_name == :arguments
|
17
17
|
- key = @dirmon_entry.job_class.keys[property_name.to_s]
|
18
|
-
- next unless key
|
18
|
+
- next unless key && key.type
|
19
19
|
- placeholder = key.default? ? key.default : nil
|
20
20
|
.form-group
|
21
21
|
= properties.label property_name.to_s
|
22
22
|
- case key.type.name
|
23
23
|
- when 'Integer'
|
24
24
|
= properties.number_field property_name, value: @dirmon_entry.properties[property_name], class: 'form-control', placeholder: placeholder
|
25
|
+
- when 'Hash'
|
26
|
+
- value = @dirmon_entry.properties[property_name]
|
27
|
+
= properties.text_field property_name, value: value ? value.to_json : '', class: 'form-control', placeholder: '{"argument1":"value1", "argument2":"value2", "argument3":"value3"}'
|
25
28
|
- when 'Array'
|
26
29
|
- options = Array(@dirmon_entry.properties[property_name])
|
27
30
|
= properties.select property_name, options_for_select(options, options), {include_hidden: false}, {class: 'selectize', multiple: true}
|