marty 5.1.4 → 5.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Gemfile +1 -1
- data/app/components/marty/data_grid_user_view.rb +5 -1
- data/app/components/marty/grid/client/grid.js +18 -0
- data/app/components/marty/main_auth_app.rb +12 -0
- data/app/components/marty/schedule_jobs_logs.rb +85 -0
- data/app/components/marty/schedule_jobs_logs/client/schedule_jobs_logs.js +15 -0
- data/app/jobs/marty/cron_job.rb +30 -0
- data/app/models/marty/background_job/log.rb +12 -0
- data/db/migrate/511_create_marty_delayed_job_logs.rb +13 -0
- data/lib/marty/version.rb +1 -1
- data/other/marty/diagnostic/database.rb +2 -1
- data/other/marty/diagnostic/scheduled_jobs.rb +25 -0
- data/spec/dummy/public/images/icons +1 -1
- data/spec/dummy/spec/features/javascripts +1 -1
- data/spec/features/schedule_jobs_logs_spec.rb +102 -0
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c09276b6e27aad355d8f9b512b7bdd753f62a19fc669757f6835337c20554f7f
|
4
|
+
data.tar.gz: 91626928a7caa158cc81628978b00d5b1a8b0266c24960c5d6164e06ef0815aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5901679d961b8484cdf274566d1f0bf8781364b0ce83a542bf1aee859f72ba6d95e8de2f71430ae5ceb86888c301e45fa0b29444ff770e60a3aed58ba64456c
|
7
|
+
data.tar.gz: 1b849061d5d1293f43e6949820426004f73fe3e6f385e72a18e33bc0bc8d52446dd854069944e77cc0dcf55549b3308930b7c0058aef5e63c36e55a22ca7fdef
|
data/Gemfile
CHANGED
@@ -17,7 +17,7 @@ module Marty
|
|
17
17
|
end
|
18
18
|
|
19
19
|
client_class do |c|
|
20
|
-
|
20
|
+
fn = l(<<~JS)
|
21
21
|
function(record) {
|
22
22
|
var sel = this.getSelectionModel().getSelection()[0];
|
23
23
|
var record_id = sel && sel.getId();
|
@@ -25,6 +25,10 @@ module Marty
|
|
25
25
|
this.server.editGrid({record_id: record_id});
|
26
26
|
}
|
27
27
|
JS
|
28
|
+
|
29
|
+
# inherited perms don't work right, set both fns to the fancy grid edit
|
30
|
+
c.do_edit_in_form = fn
|
31
|
+
c.do_view_in_form = fn
|
28
32
|
end
|
29
33
|
|
30
34
|
def default_bbar
|
@@ -159,4 +159,22 @@
|
|
159
159
|
clearFilters: function() {
|
160
160
|
this.filters.clearFilters();
|
161
161
|
},
|
162
|
+
|
163
|
+
netzkeGridSelectedDefaultAction: function(endpoint, confirmation) {
|
164
|
+
var selected = this.getSelectionModel().getSelection().map((r) => r.id)
|
165
|
+
|
166
|
+
if (confirmation) {
|
167
|
+
Ext.Msg.confirm(
|
168
|
+
confirmation,
|
169
|
+
Ext.String.format('Are you sure?'),
|
170
|
+
(btn, value, cfg) => {
|
171
|
+
if (btn == "yes") {
|
172
|
+
this.server[endpoint](selected, () => { this.unmask() })
|
173
|
+
}
|
174
|
+
}
|
175
|
+
);
|
176
|
+
} else {
|
177
|
+
this.server[endpoint](selected, () => { this.unmask() })
|
178
|
+
}
|
179
|
+
}
|
162
180
|
}
|
@@ -4,6 +4,7 @@ require 'marty/api_log_view'
|
|
4
4
|
require 'marty/config_view'
|
5
5
|
require 'marty/data_grid_view'
|
6
6
|
require 'marty/schedule_jobs_dashboard'
|
7
|
+
require 'marty/schedule_jobs_logs'
|
7
8
|
require 'marty/data_grid_user_view'
|
8
9
|
require 'marty/event_view'
|
9
10
|
require 'marty/import_type_view'
|
@@ -116,6 +117,7 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
116
117
|
:bg_stop,
|
117
118
|
:bg_restart,
|
118
119
|
:schedule_jobs_dashboard,
|
120
|
+
:schedule_jobs_logs,
|
119
121
|
]
|
120
122
|
},
|
121
123
|
]
|
@@ -295,6 +297,14 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
295
297
|
a.handler = :netzke_load_component_by_action
|
296
298
|
end
|
297
299
|
|
300
|
+
action :schedule_jobs_logs do |a|
|
301
|
+
a.text = "Schedule Job's Logs"
|
302
|
+
a.tooltip = "Show Scheduled Job's logs"
|
303
|
+
a.icon_cls = 'fa fa-cog glyph'
|
304
|
+
a.disabled = !self.class.has_perm?(:admin)
|
305
|
+
a.handler = :netzke_load_component_by_action
|
306
|
+
end
|
307
|
+
|
298
308
|
action :log_view do |a|
|
299
309
|
a.text = 'View Log'
|
300
310
|
a.tooltip = 'View Log'
|
@@ -394,6 +404,8 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
394
404
|
|
395
405
|
component :schedule_jobs_dashboard
|
396
406
|
|
407
|
+
component :schedule_jobs_logs
|
408
|
+
|
397
409
|
component :config_view
|
398
410
|
|
399
411
|
component :data_grid_view
|
@@ -0,0 +1,85 @@
|
|
1
|
+
class Marty::ScheduleJobsLogs < Marty::Grid
|
2
|
+
ACCESSIBLE_BY = [:admin]
|
3
|
+
|
4
|
+
has_marty_permissions(
|
5
|
+
read: ACCESSIBLE_BY,
|
6
|
+
create: ACCESSIBLE_BY,
|
7
|
+
update: ACCESSIBLE_BY,
|
8
|
+
delete: ACCESSIBLE_BY,
|
9
|
+
destroy: ACCESSIBLE_BY,
|
10
|
+
destroy_all: ACCESSIBLE_BY,
|
11
|
+
ignore: ACCESSIBLE_BY,
|
12
|
+
edit_window__edit_form__submit: ACCESSIBLE_BY,
|
13
|
+
add_window__add_form__submit: ACCESSIBLE_BY
|
14
|
+
)
|
15
|
+
|
16
|
+
def configure(c)
|
17
|
+
super
|
18
|
+
|
19
|
+
c.title ||= I18n.t('schedule_jobs_dashboard_view_title', default: "Scheduled Job's Logs")
|
20
|
+
c.model = 'Marty::BackgroundJob::Log'
|
21
|
+
c.paging = :buffered
|
22
|
+
c.editing = :in_form
|
23
|
+
c.multi_select = true
|
24
|
+
|
25
|
+
c.attributes = [
|
26
|
+
:job_class,
|
27
|
+
:status,
|
28
|
+
:error,
|
29
|
+
:created_at
|
30
|
+
]
|
31
|
+
|
32
|
+
c.store_config.merge!(sorters: [{ property: :id, direction: 'DESC' }])
|
33
|
+
end
|
34
|
+
|
35
|
+
def default_context_menu
|
36
|
+
[]
|
37
|
+
end
|
38
|
+
|
39
|
+
def default_bbar
|
40
|
+
[:delete, :destroy_all, :ignore]
|
41
|
+
end
|
42
|
+
|
43
|
+
attribute :job_class do |c|
|
44
|
+
c.width = 400
|
45
|
+
c.read_only = true
|
46
|
+
end
|
47
|
+
|
48
|
+
attribute :status do |c|
|
49
|
+
c.read_only = true
|
50
|
+
end
|
51
|
+
|
52
|
+
attribute :error do |c|
|
53
|
+
c.width = 800
|
54
|
+
c.read_only = true
|
55
|
+
c.getter = ->(record) { record.error.to_json }
|
56
|
+
end
|
57
|
+
|
58
|
+
action :destroy_all do |a|
|
59
|
+
a.text = 'Delete all'
|
60
|
+
a.tooltip = 'Delete all logs'
|
61
|
+
a.icon_cls = 'fa fa-trash glyph'
|
62
|
+
end
|
63
|
+
|
64
|
+
action :ignore do |a|
|
65
|
+
a.text = 'Ignore in diag'
|
66
|
+
a.tooltip = 'Ignore in diag'
|
67
|
+
a.icon_cls = 'fa fa-trash glyph'
|
68
|
+
end
|
69
|
+
|
70
|
+
endpoint :destroy_all do
|
71
|
+
Marty::BackgroundJob::Log.delete_all
|
72
|
+
client.reload
|
73
|
+
end
|
74
|
+
|
75
|
+
endpoint :ignore do |ids|
|
76
|
+
Marty::BackgroundJob::Log.
|
77
|
+
where(id: ids).
|
78
|
+
where(status: :failure).
|
79
|
+
each { |record| record.update(status: :failure_ignore) }
|
80
|
+
|
81
|
+
client.reload
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
ScheduleJobsLogs = Marty::ScheduleJobsLogs
|
@@ -0,0 +1,15 @@
|
|
1
|
+
{
|
2
|
+
netzkeOnDestroyAll: function(params) {
|
3
|
+
Ext.Msg.confirm(
|
4
|
+
'Delete all',
|
5
|
+
Ext.String.format('Are you sure?'),
|
6
|
+
(btn, value, cfg) => {
|
7
|
+
if (btn == "yes") {
|
8
|
+
this.mask('Deleting...');
|
9
|
+
this.server.destroyAll(() => { this.unmask()});
|
10
|
+
}
|
11
|
+
});
|
12
|
+
},
|
13
|
+
|
14
|
+
netzkeOnIgnore: function(_) { return this.netzkeGridSelectedDefaultAction('ignore') }
|
15
|
+
}
|
data/app/jobs/marty/cron_job.rb
CHANGED
@@ -1,4 +1,34 @@
|
|
1
1
|
class Marty::CronJob < ActiveJob::Base
|
2
|
+
around_perform do |_job, block|
|
3
|
+
begin
|
4
|
+
block.call
|
5
|
+
log_success
|
6
|
+
rescue StandardError => e
|
7
|
+
log_failure(e)
|
8
|
+
raise e
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def log_failure(exception)
|
13
|
+
error = {
|
14
|
+
message: exception.message,
|
15
|
+
backtrace: exception.backtrace
|
16
|
+
}
|
17
|
+
|
18
|
+
::Marty::BackgroundJob::Log.create!(
|
19
|
+
job_class: self.class.name,
|
20
|
+
status: :failure,
|
21
|
+
error: error
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def log_success
|
26
|
+
::Marty::BackgroundJob::Log.create!(
|
27
|
+
job_class: self.class.name,
|
28
|
+
status: :success
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
2
32
|
class << self
|
3
33
|
def schedule
|
4
34
|
return reschedule if scheduled?
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Marty
|
2
|
+
module BackgroundJob
|
3
|
+
class Log < Marty::Base
|
4
|
+
self.table_name = 'marty_background_job_logs'
|
5
|
+
|
6
|
+
validates :job_class, :status, presence: true
|
7
|
+
|
8
|
+
ALL_STATUSES = %w[success failure failure_ignore].freeze
|
9
|
+
enum status: ALL_STATUSES.zip(ALL_STATUSES).to_h
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateMartyDelayedJobLogs < ActiveRecord::Migration[5.1]
|
2
|
+
def change
|
3
|
+
create_table :marty_background_job_logs do |t|
|
4
|
+
t.string :job_class, null: false
|
5
|
+
t.string :status, null: false
|
6
|
+
t.jsonb :error
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
|
11
|
+
add_index :marty_background_job_logs, :job_class
|
12
|
+
end
|
13
|
+
end
|
data/lib/marty/version.rb
CHANGED
@@ -20,8 +20,9 @@ module Marty::Diagnostic::Database
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def self.db_schema
|
23
|
-
current = ActiveRecord::
|
23
|
+
current = ActiveRecord::Migrator.current_version
|
24
24
|
raise "Migration is needed.\nCurrent Version: #{current}" if
|
25
|
+
Rails.version >= '5.2.0' &&
|
25
26
|
ActiveRecord::Base.connection.migration_context.needs_migration?
|
26
27
|
|
27
28
|
current.to_s
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Marty::Diagnostic; class ScheduledJobs < Base
|
2
|
+
self.aggregatable = false
|
3
|
+
|
4
|
+
diagnostic_fn do
|
5
|
+
logs = ::Marty::BackgroundJob::Log.
|
6
|
+
order(job_class: :asc, status: :desc, id: :desc).
|
7
|
+
select('DISTINCT ON(job_class, status) *').
|
8
|
+
where.not(status: :failure_ignore).
|
9
|
+
first(1000)
|
10
|
+
|
11
|
+
failed_total = ::Marty::BackgroundJob::Log.where(status: :failure).count
|
12
|
+
|
13
|
+
result = logs.each_with_object({}) do |log, hash|
|
14
|
+
message = "Status: #{log.status}, last_run: #{log.created_at}"
|
15
|
+
message = "#{message}, error: #{log.error}" if log.failure?
|
16
|
+
hash[log.job_class] = log.success? ? message : error(message)
|
17
|
+
end
|
18
|
+
|
19
|
+
result['Failures total'] = 0
|
20
|
+
result['Failures total'] = error(failed_total) if failed_total != 0
|
21
|
+
|
22
|
+
result
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
../extjs/icons/
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
../../../features/javascripts/
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
feature 'Schedule Jobs Logs', js: true do
|
4
|
+
before do
|
5
|
+
populate_test_users
|
6
|
+
end
|
7
|
+
|
8
|
+
context 'as dev' do
|
9
|
+
before do
|
10
|
+
log_in_as('dev1')
|
11
|
+
wait_for_ajax
|
12
|
+
press('System')
|
13
|
+
press('Background Jobs')
|
14
|
+
press("Schedule Job's Logs")
|
15
|
+
wait_for_ajax
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'access denied' do
|
19
|
+
expect(page).to_not have_content "Schedule Job's Logs"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'as admin' do
|
24
|
+
let(:grid_view) { netzke_find('schedule_jobs_logs') }
|
25
|
+
|
26
|
+
let!(:create_logs) do
|
27
|
+
Marty::BackgroundJob::Log.create!(
|
28
|
+
job_class: 'TestJob2',
|
29
|
+
status: :success,
|
30
|
+
created_at: 3.minutes.ago
|
31
|
+
)
|
32
|
+
|
33
|
+
Marty::BackgroundJob::Log.create!(
|
34
|
+
job_class: 'TestJob2',
|
35
|
+
status: :failure,
|
36
|
+
error: { message: 'Test error message', backtrace: '' },
|
37
|
+
created_at: 2.minutes.ago
|
38
|
+
)
|
39
|
+
|
40
|
+
Marty::BackgroundJob::Log.create!(
|
41
|
+
job_class: 'Another Test Job',
|
42
|
+
status: :success,
|
43
|
+
created_at: 1.minute.ago
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
before do
|
48
|
+
log_in_as('admin1')
|
49
|
+
wait_for_ajax
|
50
|
+
press('System')
|
51
|
+
press('Background Jobs')
|
52
|
+
press("Schedule Job's Logs")
|
53
|
+
|
54
|
+
wait_for_ajax
|
55
|
+
|
56
|
+
expect(page).to have_content "Scheduled Job's Logs"
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'shows logs' do
|
60
|
+
class_names = grid_view.get_col_vals('job_class', 3, 0)
|
61
|
+
|
62
|
+
expect(class_names.uniq).to eq ['Another Test Job', 'TestJob2']
|
63
|
+
|
64
|
+
statuses = grid_view.get_col_vals('status', 3, 0)
|
65
|
+
expect(statuses).to eq ['success', 'failure', 'success']
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'deletes log' do
|
69
|
+
find('.x-grid-item', text: 'Another Test Job').click
|
70
|
+
press 'Delete'
|
71
|
+
press 'Yes'
|
72
|
+
|
73
|
+
wait_for_ajax
|
74
|
+
|
75
|
+
class_names = grid_view.get_col_vals('job_class', 2, 0)
|
76
|
+
expect(class_names.uniq).to eq ['TestJob2']
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'deletes all logs' do
|
80
|
+
press 'Delete all'
|
81
|
+
press 'Yes'
|
82
|
+
|
83
|
+
wait_for_ajax
|
84
|
+
|
85
|
+
expect(grid_view.row_count).to eq 0
|
86
|
+
expect(Marty::BackgroundJob::Log.count).to eq 0
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'marks as ignored in diags' do
|
90
|
+
expect(Marty::BackgroundJob::Log.failure_ignore.count).to eq 0
|
91
|
+
find('.x-grid-item', text: 'Test error').click
|
92
|
+
press 'Ignore in diag'
|
93
|
+
press 'Yes'
|
94
|
+
|
95
|
+
wait_for_ajax
|
96
|
+
|
97
|
+
statuses = grid_view.get_col_vals('status', 3, 0)
|
98
|
+
expect(statuses).to eq ['success', 'failure_ignore', 'success']
|
99
|
+
expect(Marty::BackgroundJob::Log.failure_ignore.count).to eq 1
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: marty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arman Bostani
|
@@ -14,7 +14,7 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date: 2019-
|
17
|
+
date: 2019-09-09 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: aws-sigv4
|
@@ -293,6 +293,8 @@ files:
|
|
293
293
|
- app/components/marty/reporting/client/reporting.js
|
294
294
|
- app/components/marty/schedule_jobs_dashboard.rb
|
295
295
|
- app/components/marty/schedule_jobs_dashboard/client/schedule_jobs_dashboard.js
|
296
|
+
- app/components/marty/schedule_jobs_logs.rb
|
297
|
+
- app/components/marty/schedule_jobs_logs/client/schedule_jobs_logs.js
|
296
298
|
- app/components/marty/script_form.rb
|
297
299
|
- app/components/marty/script_form/client/script_form.js
|
298
300
|
- app/components/marty/script_grid.rb
|
@@ -319,6 +321,7 @@ files:
|
|
319
321
|
- app/models/marty/api_auth.rb
|
320
322
|
- app/models/marty/api_config.rb
|
321
323
|
- app/models/marty/background_job.rb
|
324
|
+
- app/models/marty/background_job/log.rb
|
322
325
|
- app/models/marty/background_job/schedule.rb
|
323
326
|
- app/models/marty/base.rb
|
324
327
|
- app/models/marty/base_rule.rb
|
@@ -412,6 +415,7 @@ files:
|
|
412
415
|
- db/migrate/507_migrate_marty_roles_to_enum.rb
|
413
416
|
- db/migrate/508_add_not_to_data_grids_tables.rb
|
414
417
|
- db/migrate/509_update_dg_plpgsql_v1_fns.rb
|
418
|
+
- db/migrate/511_create_marty_delayed_job_logs.rb
|
415
419
|
- db/seeds.rb
|
416
420
|
- db/sql/lookup_grid_distinct_v1.sql
|
417
421
|
- db/sql/query_grid_dir_v1.sql
|
@@ -476,6 +480,7 @@ files:
|
|
476
480
|
- other/marty/diagnostic/packer.rb
|
477
481
|
- other/marty/diagnostic/reporter.rb
|
478
482
|
- other/marty/diagnostic/request.rb
|
483
|
+
- other/marty/diagnostic/scheduled_jobs.rb
|
479
484
|
- other/marty/diagnostic/version.rb
|
480
485
|
- script/rails
|
481
486
|
- spec/controllers/application_controller_spec.rb
|
@@ -1600,6 +1605,7 @@ files:
|
|
1600
1605
|
- spec/features/reporting_spec.rb
|
1601
1606
|
- spec/features/rule_spec.rb
|
1602
1607
|
- spec/features/schedule_jobs_dashboard_spec.rb
|
1608
|
+
- spec/features/schedule_jobs_logs_spec.rb
|
1603
1609
|
- spec/features/scripting_spec.rb
|
1604
1610
|
- spec/features/scripting_test_spec.rb
|
1605
1611
|
- spec/features/user_view_spec.rb
|
@@ -1694,8 +1700,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1694
1700
|
- !ruby/object:Gem::Version
|
1695
1701
|
version: '0'
|
1696
1702
|
requirements: []
|
1697
|
-
|
1698
|
-
rubygems_version: 2.6.14
|
1703
|
+
rubygems_version: 3.0.3
|
1699
1704
|
signing_key:
|
1700
1705
|
specification_version: 4
|
1701
1706
|
summary: A framework for working with versioned data
|