rocketjob_mission_control 1.2.0 → 1.2.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.
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