marty 5.1.4 → 5.2.0
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 +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
|