rocketjob_mission_control 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c8d7c96f03155c733cf07a5e81796020552dd378
4
- data.tar.gz: cf0647850f7b019530b1f1c6d4a511dbcb5fcc5b
3
+ metadata.gz: 304c034afa2db7c0db432bc35a23cf61a98bb0ea
4
+ data.tar.gz: af4d336900d12e6f2aa7b3913e024ff7bd3dec8b
5
5
  SHA512:
6
- metadata.gz: 4639ef836e562dc597c5e0651571111ac84b3a217b3599da8f06807513375c73b44eb9a091517da37c57f6fa9d478fa2f23f75825ef6c8afad0e899f4892d67b
7
- data.tar.gz: fe70a9fd5c6cbd029443dda89be419f9c08b6de28fe3a90f2908bccd753f3d4c5837fb239e9d970170e3849c7086e33d9ee5b38518298676b0844308298b9303
6
+ metadata.gz: 322c4304792cba14b21561dbea0e3f33e7bcbe44db1dd4a21ae5598b9e9e8af4ae32a7e02419cc37344e3a687ac5e8089694d790ee00345cb3470a8b9026d0bb
7
+ data.tar.gz: 8c512bd2504b5f0dfd1acff972d661219a45d8ec53c4dd7c43696f62e10b94acb7d0c4301dbab2ec2831e8b38d3647b46203de897014d18644690e9e424eac8e
@@ -47,3 +47,6 @@
47
47
  .callout-alert-top {
48
48
  border-top-color: #ce4844;
49
49
  }
50
+ .callout-zombie-top {
51
+ border-top-color: darkred;
52
+ }
@@ -76,15 +76,14 @@ module RocketJobMissionControl
76
76
  private
77
77
 
78
78
  def parse_and_assign_arguments
79
- if arguments = params[:rocket_job_dirmon_entry][:arguments]
80
- begin
81
- arguments = JSON.parse(arguments)
82
- @dirmon_entry.arguments = arguments.kind_of?(Array) ? arguments : [arguments]
83
- rescue JSON::ParserError => e
84
- @dirmon_entry.errors.add(:arguments, e.message)
85
- end
79
+ arguments = params[:rocket_job_dirmon_entry][:arguments]
80
+ arguments = arguments.blank? ? '[]' : arguments
81
+ begin
82
+ arguments = JSON.parse(arguments)
83
+ @dirmon_entry.arguments = arguments.kind_of?(Array) ? arguments : [arguments]
84
+ rescue JSON::ParserError => e
85
+ @dirmon_entry.errors.add(:arguments, e.message)
86
86
  end
87
-
88
87
  end
89
88
 
90
89
  def clean_values
@@ -116,7 +115,7 @@ module RocketJobMissionControl
116
115
  def dirmon_params
117
116
  params
118
117
  .require(:rocket_job_dirmon_entry)
119
- .permit(:name, :archive_directory, :pattern, :job_class_name).tap do |whitelist|
118
+ .permit(:name, :archive_directory, :pattern, :job_class_name, :perform_method).tap do |whitelist|
120
119
  whitelist[:properties] = params[:rocket_job_dirmon_entry][:properties] if params[:rocket_job_dirmon_entry][:properties]
121
120
  end
122
121
  end
@@ -7,21 +7,25 @@ module RocketJobMissionControl
7
7
 
8
8
  if @job && @job.failed?
9
9
  @slice_errors = job_failures.list
10
- @error_type = params[:error_type] || @slice_errors.first['_id']['error_class']
11
10
 
12
- offset = params.fetch(:offset, 1).to_i
13
- selected_exception = job_failures.for_error(@error_type, offset)
14
- current_failure = selected_exception.first
11
+ if @slice_errors.present?
12
+ @error_type = params[:error_type] || @slice_errors.first['_id']['error_class']
15
13
 
16
- @pagination = {
17
- offset: offset,
18
- total: (selected_exception.count - 1),
19
- }
14
+ offset = params.fetch(:offset, 0).to_i
15
+ selected_exception = job_failures.for_error(@error_type, offset)
16
+ current_failure = selected_exception.first
20
17
 
21
- if current_failure.present?
22
- @failure_exception = current_failure['exception']
23
- end
18
+ @pagination = {
19
+ offset: offset,
20
+ total: (selected_exception.count - 1),
21
+ }
24
22
 
23
+ if current_failure.present?
24
+ @failure_exception = current_failure['exception']
25
+ end
26
+ else
27
+ flash[:notice] = t(:no_errors, scope: [:job, :failures])
28
+ end
25
29
  else
26
30
  redirect_to(job_path(params[:job_id]))
27
31
  end
@@ -6,12 +6,17 @@ module RocketJobMissionControl
6
6
  @workers = RocketJob::Worker.sort(:name)
7
7
  end
8
8
 
9
- VALID_STATES = { stop: 'stopped', pause: 'paused', resume: 'resumed' }
9
+ VALID_STATES = {
10
+ stop_all: 'stopped',
11
+ pause_all: 'paused',
12
+ resume_all: 'resumed',
13
+ destroy_zombies: 'destroyed if zombified',
14
+ }
10
15
 
11
16
  def update_all
12
17
  worker_action = params[:worker_action].to_sym
13
18
  if VALID_STATES.keys.include?(worker_action)
14
- RocketJob::Worker.send("#{worker_action}_all".to_sym)
19
+ RocketJob::Worker.send(worker_action.to_sym)
15
20
  flash[:notice] = t(:success, scope: [:worker, :update_all], worker_action: VALID_STATES[worker_action])
16
21
  else
17
22
  flash[:alert] = t(:invalid, scope: [:worker, :update_all])
@@ -2,12 +2,16 @@ module RocketJobMissionControl
2
2
  module WorkersHelper
3
3
 
4
4
  def worker_card_class(worker)
5
- map = {
6
- running: 'callout-success-top',
7
- paused: 'callout-warning-top',
8
- stopping: 'callout-alert-top',
9
- }
10
- map[worker.state] || 'callout-info-top'
5
+ if worker.zombie?
6
+ 'callout-zombie-top'
7
+ else
8
+ map = {
9
+ running: 'callout-success-top',
10
+ paused: 'callout-warning-top',
11
+ stopping: 'callout-alert-top',
12
+ }
13
+ map[worker.state] || 'callout-info-top'
14
+ end
11
15
  end
12
16
 
13
17
  end
@@ -27,7 +27,7 @@
27
27
  #page-content-wrapper
28
28
  = render partial: 'layouts/rocket_job_mission_control/partials/header'
29
29
 
30
- .flash
30
+ .flash.text-center
31
31
  - flash.each do |key, msg|
32
32
  - if msg
33
33
  .alert{class: "alert-#{key} alert-dismissable", role: 'alert'}
@@ -18,6 +18,9 @@
18
18
  .job.form-group
19
19
  = f.label :job_class_name
20
20
  = f.text_field :job_class_name, class: 'form-control'
21
+ .job.form-group
22
+ = f.label :perform_method
23
+ = f.text_field :perform_method, class: 'form-control'
21
24
  .job_arguments.form-group
22
25
  = f.label :arguments
23
26
  = f.text_area :arguments,
@@ -7,6 +7,9 @@
7
7
  %div
8
8
  %label Job Class Name:
9
9
  = @dirmon_entry.job_class_name
10
+ %div
11
+ %label Perform Method:
12
+ = @dirmon_entry.perform_method
10
13
  %div
11
14
  %label Archive Directory:
12
15
  = @dirmon_entry.archive_directory
@@ -17,7 +17,8 @@
17
17
  - if job.kind_of?(RocketJob::SlicedJob)
18
18
  .slice_count
19
19
  %label Slices Running:
20
- = job.input.find_all { |s| s.state == :running }.count
20
+ -#= job.input.find_all { |s| s.state == :running }.count
21
+ = job.input.collection.aggregate([{ '$match' => { state: 'queued' } },{ '$group' => { _id: nil, count: { '$sum' => 1 } } }] )
21
22
  - else
22
23
  .worker
23
24
  %label Worker:
@@ -5,11 +5,11 @@
5
5
  %ol.breadcrumb{ style: 'margin-bottom: 0'}
6
6
  %li.active Workers
7
7
  .btn-group.pull-right
8
- - [:stop, :pause, :resume].each do |action|
9
- = link_to("#{action.to_s.capitalize} All",
8
+ - [:stop_all, :pause_all, :resume_all, :destroy_zombies].each do |action|
9
+ = link_to("#{action.to_s.humanize.capitalize}",
10
10
  rocket_job_mission_control.update_all_workers_path(worker_action: action),
11
11
  method: :patch,
12
- data: { confirm: t(:confirm, scope: [:worker, :update_all], action: action) },
12
+ data: { confirm: t(:confirm, scope: [:worker, :update_all], action: action.to_s.singularize.humanize.downcase) },
13
13
  class: 'btn btn-default')
14
14
  .clearfix
15
15
 
@@ -37,7 +37,11 @@
37
37
 
38
38
  .time
39
39
  %b Started:
40
- = worker.started_at.strftime("%b, %d %Y at %l:%M %p")
40
+ = "#{RocketJob.seconds_as_duration(Time.now - worker.started_at)} ago"
41
+
42
+ .heartbeat
43
+ %b Last Heartbeat:
44
+ = "#{RocketJob.seconds_as_duration(Time.now - worker.heartbeat.updated_at)} ago"
41
45
 
42
46
  .actions
43
47
  = render partial: 'actions', locals: { worker: worker }
@@ -52,12 +52,14 @@ en:
52
52
  update_all:
53
53
  success: "Workers have been %{worker_action}."
54
54
  invalid: "Action not allowed."
55
- confirm: "Are you sure you want to %{action} all workers?"
55
+ confirm: "Are you sure you want to %{action} workers?"
56
56
  job:
57
57
  find:
58
58
  failure: "Could not find job with id: %{id}!"
59
59
  action:
60
60
  confirm: "Are you sure you want to %{action} this job?"
61
+ failures:
62
+ no_errors: 'No slice failures present.'
61
63
 
62
64
  dirmon_entry:
63
65
  find:
@@ -1,3 +1,3 @@
1
1
  module RocketJobMissionControl
2
- VERSION = '1.2.0'
2
+ VERSION = '1.2.1'
3
3
  end
@@ -5,6 +5,11 @@ class FakeButGoodJob < RocketJob::Job
5
5
  def perform(id)
6
6
  id
7
7
  end
8
+
9
+ def perform_with_no_params
10
+ 100_000
11
+ end
12
+
8
13
  end
9
14
 
10
15
  module RocketJobMissionControl
@@ -185,52 +190,61 @@ module RocketJobMissionControl
185
190
 
186
191
  describe 'POST #create' do
187
192
  context 'with valid parameters' do
188
- let(:dirmon_params) do
189
- {
190
- name: 'Test',
191
- pattern: '/files/',
192
- job_class_name: 'FakeButGoodJob',
193
- arguments: [ 42 ].to_json,
194
- properties: { description: '', priority: 42 },
195
- }
196
- end
197
193
 
198
- before do
199
- post :create, rocket_job_dirmon_entry: dirmon_params
200
- end
194
+ {
195
+ perform: { argument: [42].to_json, expected_value: [42] },
196
+ perform_with_no_params: { argument: '', expected_value: [] },
197
+ }.each_pair do |perform_method, arguments|
198
+ context "and arguments are '#{arguments}'" do
199
+ let(:dirmon_params) do
200
+ {
201
+ name: 'Test',
202
+ pattern: '/files/',
203
+ job_class_name: 'FakeButGoodJob',
204
+ arguments: arguments[:argument],
205
+ properties: { description: '', priority: 42 },
206
+ perform_method: perform_method,
207
+ }
208
+ end
201
209
 
202
- it 'creates the entry' do
203
- expect(assigns(:dirmon_entry)).to be_persisted
204
- end
210
+ before do
211
+ post :create, rocket_job_dirmon_entry: dirmon_params
212
+ end
205
213
 
206
- it 'has no errors' do
207
- expect(assigns(:dirmon_entry).errors.messages).to be_empty
208
- end
214
+ it 'creates the entry' do
215
+ expect(assigns(:dirmon_entry)).to be_persisted
216
+ end
209
217
 
210
- it 'redirects to created entry' do
211
- expect(response).to redirect_to(dirmon_entry_path(assigns(:dirmon_entry)))
212
- end
218
+ it 'has no errors' do
219
+ expect(assigns(:dirmon_entry).errors.messages).to be_empty
220
+ end
213
221
 
214
- it 'does not load all entries' do
215
- expect(dirmon_list).to_not have_received(:sort)
216
- end
222
+ it 'redirects to created entry' do
223
+ expect(response).to redirect_to(dirmon_entry_path(assigns(:dirmon_entry)))
224
+ end
217
225
 
218
- it 'does not save blank properties' do
219
- expect(assigns(:dirmon_entry).properties[:description]).to eq(nil)
220
- end
226
+ it 'does not load all entries' do
227
+ expect(dirmon_list).to_not have_received(:sort)
228
+ end
221
229
 
222
- it 'saves properties' do
223
- expect(assigns(:dirmon_entry).properties[:priority]).to eq('42')
224
- end
230
+ it 'does not save blank properties' do
231
+ expect(assigns(:dirmon_entry).properties[:description]).to eq(nil)
232
+ end
225
233
 
226
- [:name, :pattern, :job_class_name].each do |attribute|
227
- it "assigns the correct value for #{attribute}" do
228
- expect(assigns(:dirmon_entry)[attribute]).to eq(dirmon_params[attribute])
229
- end
230
- end
234
+ it 'saves properties' do
235
+ expect(assigns(:dirmon_entry).properties[:priority]).to eq('42')
236
+ end
231
237
 
232
- it 'persists arguments correctly' do
233
- expect(assigns(:dirmon_entry).arguments).to eq([42])
238
+ [:name, :pattern, :job_class_name].each do |attribute|
239
+ it "assigns the correct value for #{attribute}" do
240
+ expect(assigns(:dirmon_entry)[attribute]).to eq(dirmon_params[attribute])
241
+ end
242
+ end
243
+
244
+ it 'persists arguments correctly' do
245
+ expect(assigns(:dirmon_entry).arguments).to eq(arguments[:expected_value])
246
+ end
247
+ end
234
248
  end
235
249
  end
236
250
 
@@ -29,17 +29,39 @@ module RocketJobMissionControl
29
29
  get :index, job_id: job.id
30
30
  end
31
31
 
32
- it 'succeeds' do
33
- expect(response).to be_success
32
+ context 'with slice errors' do
33
+ it 'succeeds' do
34
+ expect(response).to be_success
35
+ end
36
+ it 'returns the job' do
37
+ expect(assigns(:job)).to eq(job)
38
+ end
39
+ it 'returns the errors' do
40
+ expect(assigns(:slice_errors)).to eq(slice_errors)
41
+ end
42
+ it 'returns the first exception' do
43
+ expect(assigns(:failure_exception)).to eq(current_failure['exception'])
44
+ end
34
45
  end
35
- it 'returns the job' do
36
- expect(assigns(:job)).to eq(job)
37
- end
38
- it 'returns the errors' do
39
- expect(assigns(:slice_errors)).to eq(slice_errors)
40
- end
41
- it 'returns the first exception' do
42
- expect(assigns(:failure_exception)).to eq(current_failure['exception'])
46
+
47
+ context 'with no slice errors' do
48
+ let(:slice_errors) { [] }
49
+
50
+ it 'succeeds' do
51
+ expect(response).to be_success
52
+ end
53
+ it 'returns the job' do
54
+ expect(assigns(:job)).to eq(job)
55
+ end
56
+ it 'returns no errors' do
57
+ expect(assigns(:slice_errors)).to eq(slice_errors)
58
+ end
59
+ it 'returns no exception' do
60
+ expect(assigns(:failure_exception)).to be_nil
61
+ end
62
+ it 'notifies the user' do
63
+ expect(flash[:notice]).to eq(I18n.t(:no_errors, scope: [:job, :failures]))
64
+ end
43
65
  end
44
66
  end
45
67
 
@@ -49,7 +49,7 @@ module RocketJobMissionControl
49
49
  RocketJobMissionControl::WorkersController::VALID_STATES.each do |worker_action, action_message|
50
50
  context "with '#{worker_action}' as the worker_action param" do
51
51
  before do
52
- allow(RocketJob::Worker).to receive("#{worker_action}_all".to_sym)
52
+ allow(RocketJob::Worker).to receive(worker_action.to_sym)
53
53
  patch :update_all, worker_action: worker_action
54
54
  end
55
55