naf 2.0.4 → 2.1.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.
- data/README.rdoc +28 -4
- data/RELEASE_NOTES.rdoc +8 -0
- data/app/assets/javascripts/dataTablesTemplates/application_schedules.js +72 -0
- data/app/assets/javascripts/dataTablesTemplates/applications.js +12 -21
- data/app/controllers/naf/application_schedule_affinity_tabs_controller.rb +5 -8
- data/app/controllers/naf/application_schedules_controller.rb +98 -0
- data/app/controllers/naf/applications_controller.rb +6 -98
- data/app/controllers/naf/historical_jobs_controller.rb +18 -8
- data/app/helpers/naf/application_helper.rb +47 -22
- data/app/models/logical/naf/application.rb +9 -126
- data/app/models/logical/naf/application_schedule.rb +186 -0
- data/app/models/logical/naf/construction_zone/boss.rb +4 -5
- data/app/models/logical/naf/construction_zone/foreman.rb +34 -13
- data/app/models/logical/naf/construction_zone/proletariat.rb +1 -0
- data/app/models/logical/naf/construction_zone/work_order.rb +11 -4
- data/app/models/logical/naf/job_fetcher.rb +1 -0
- data/app/models/naf/application.rb +5 -16
- data/app/models/naf/application_schedule.rb +117 -43
- data/app/models/naf/historical_job.rb +6 -3
- data/app/models/naf/queued_job.rb +3 -0
- data/app/models/naf/run_interval_style.rb +20 -0
- data/app/models/naf/running_job.rb +3 -0
- data/app/models/process/naf/data_migration/backfill_application_schedule_run_interval.rb +85 -0
- data/app/models/process/naf/log_archiver.rb +1 -1
- data/app/models/process/naf/log_reader.rb +141 -0
- data/app/models/process/naf/runner.rb +6 -49
- data/app/views/naf/application_schedule_affinity_tabs/_form.html.erb +1 -1
- data/app/views/naf/{applications → application_schedules}/_application_schedule_prerequisites.html.erb +1 -1
- data/app/views/naf/application_schedules/_form.html.erb +120 -0
- data/app/views/naf/application_schedules/edit.html.erb +11 -0
- data/app/views/naf/application_schedules/index.html.erb +47 -0
- data/app/views/naf/application_schedules/index.json.erb +8 -0
- data/app/views/naf/application_schedules/new.html.erb +11 -0
- data/app/views/naf/application_schedules/show.html.erb +130 -0
- data/app/views/naf/applications/_form.html.erb +44 -106
- data/app/views/naf/applications/_search_container.html.erb +29 -29
- data/app/views/naf/applications/index.html.erb +1 -10
- data/app/views/naf/applications/index.json.erb +22 -6
- data/app/views/naf/applications/show.html.erb +47 -97
- data/app/views/naf/logger_styles/_form.html.erb +0 -3
- data/app/views/naf/machines/_form.html.erb +3 -4
- data/config/routes.rb +3 -4
- data/db/migrate/20131219195439_add_run_interval_styles_table.rb +49 -0
- data/db/migrate/20140113183243_drop_run_start_minute_from_application_schedules.rb +18 -0
- data/lib/naf/version.rb +1 -1
- data/naf.gemspec +1 -1
- data/spec/controllers/naf/application_schedule_affinity_tabs_controller_spec.rb +34 -27
- data/spec/controllers/naf/applications_controller_spec.rb +0 -48
- data/spec/factories/naf.rb +14 -8
- data/spec/models/logical/naf/application_spec.rb +9 -37
- data/spec/models/logical/naf/machine_spec.rb +1 -1
- data/spec/models/naf/application_schedule_spec.rb +38 -50
- data/spec/models/naf/application_spec.rb +3 -3
- data/spec/models/naf/historical_job_spec.rb +4 -2
- data/spec/models/naf/queued_job_spec.rb +2 -0
- data/spec/models/naf/run_interval_style_spec.rb +28 -0
- data/spec/models/naf/running_job_spec.rb +2 -0
- metadata +19 -7
- data/app/models/logical/naf/job_creator.rb +0 -151
- data/app/views/naf/applications/_application_schedule.html.erb +0 -80
- data/spec/models/logical/naf/job_creator_spec.rb +0 -102
@@ -80,12 +80,11 @@ module Logical::Naf::ConstructionZone
|
|
80
80
|
def enqueue_n_commands_on_machines(parameters, number_of_jobs = :from_limit, machines = [])
|
81
81
|
logger.detail "enqueuing #{parameters[:command]} #{number_of_jobs} time(s) on #{machines.length} machine(s)"
|
82
82
|
machines.each do |machine|
|
83
|
-
number_of_jobs = (parameters[:
|
83
|
+
number_of_jobs = (parameters[:application_run_group_quantum] || 1) if number_of_jobs == :from_limit
|
84
84
|
logger.info "enqueuing #{parameters[:command]} #{number_of_jobs} time(s) on #{machine}"
|
85
85
|
(1..number_of_jobs).each do
|
86
86
|
machine_parameters = {
|
87
|
-
:
|
88
|
-
:application_run_group_restriction => ::Naf::ApplicationRunGroupRestriction.limited_per_machine
|
87
|
+
application_run_group_restriction: ::Naf::ApplicationRunGroupRestriction.limited_per_machine
|
89
88
|
}.merge(parameters)
|
90
89
|
machine_parameters[:affinities] =
|
91
90
|
[machine.affinity] + if machine_parameters[:affinities].nil?
|
@@ -102,10 +101,10 @@ module Logical::Naf::ConstructionZone
|
|
102
101
|
end
|
103
102
|
|
104
103
|
def enqueue_n_commands(parameters, number_of_jobs = :from_limit)
|
105
|
-
number_of_jobs = (parameters[:
|
104
|
+
number_of_jobs = (parameters[:application_run_group_quantum] || 1) if number_of_jobs == :from_limit
|
106
105
|
logger.info "enqueuing #{parameters[:command]} #{number_of_jobs} time(s) on #{machine}"
|
107
106
|
(1..number_of_jobs).each do
|
108
|
-
work_order = AdHocWorkOrder.new(
|
107
|
+
work_order = AdHocWorkOrder.new(parameters)
|
109
108
|
@foreman.enqueue(work_order)
|
110
109
|
end
|
111
110
|
end
|
@@ -11,7 +11,8 @@ module Logical::Naf::ConstructionZone
|
|
11
11
|
unless work_order.enqueue_backlogs
|
12
12
|
if limited_by_run_group?(work_order.application_run_group_restriction,
|
13
13
|
work_order.application_run_group_name,
|
14
|
-
work_order.application_run_group_limit
|
14
|
+
work_order.application_run_group_limit,
|
15
|
+
work_order.historical_job_affinity_tab_parameters)
|
15
16
|
logger.warn "work order limited by run queue limits #{work_order.inspect}"
|
16
17
|
return nil
|
17
18
|
end
|
@@ -21,26 +22,46 @@ module Logical::Naf::ConstructionZone
|
|
21
22
|
work_order.historical_job_prerequisite_historical_jobs)
|
22
23
|
end
|
23
24
|
|
24
|
-
def limited_by_run_group?(application_run_group_restriction, application_run_group_name, application_run_group_limit)
|
25
|
+
def limited_by_run_group?(application_run_group_restriction, application_run_group_name, application_run_group_limit, affinities)
|
25
26
|
if (application_run_group_restriction.id == ::Naf::ApplicationRunGroupRestriction.no_limit.id ||
|
26
27
|
application_run_group_limit.nil? ||
|
27
28
|
application_run_group_name.nil?)
|
28
29
|
false
|
29
30
|
elsif application_run_group_restriction.id == ::Naf::ApplicationRunGroupRestriction.limited_per_machine.id
|
30
|
-
#
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
# Retrieve the affinity associated to the machine
|
32
|
+
machine_affinity = nil
|
33
|
+
affinities.each do |affinity|
|
34
|
+
machine_affinity = ::Naf::Affinity.find_by_id(affinity[:affinity_id])
|
35
|
+
if machine_affinity.affinity_classification_name == 'machine'
|
36
|
+
break
|
37
|
+
end
|
38
|
+
end
|
34
39
|
|
35
|
-
#
|
36
|
-
|
37
|
-
|
40
|
+
# If affinity is present, check if the sum of jobs running on the machine
|
41
|
+
# and queued for the machine is less the application_run_group_limit.
|
42
|
+
# If affinity is not present, send a log warning the user that application schedule
|
43
|
+
# should have affinity associated to the machine in order to behave correctly, and
|
44
|
+
# queue the application.
|
45
|
+
if machine_affinity.present?
|
46
|
+
queued_jobs = ::Naf::QueuedJob.
|
47
|
+
joins(:historical_job).
|
48
|
+
joins("INNER JOIN #{Naf.schema_name}.historical_job_affinity_tabs AS hjat
|
49
|
+
ON hjat.historical_job_id = #{Naf.schema_name}.historical_jobs.id").
|
50
|
+
where("#{Naf.schema_name}.historical_jobs.application_run_group_name = ? AND hjat.affinity_id = ?",
|
51
|
+
application_run_group_name, machine_affinity.id).count
|
52
|
+
running_jobs = ::Naf::RunningJob.where(
|
53
|
+
application_run_group_name: application_run_group_name,
|
54
|
+
started_on_machine_id: machine_affinity.affinity_name
|
55
|
+
).count
|
38
56
|
|
39
|
-
|
40
|
-
|
57
|
+
queued_jobs + running_jobs >= application_run_group_limit
|
58
|
+
else
|
59
|
+
logger.warn "application schedule does not have affinity associated with a machine"
|
60
|
+
false
|
61
|
+
end
|
41
62
|
elsif application_run_group_restriction.id == ::Naf::ApplicationRunGroupRestriction.limited_per_all_machines.id
|
42
|
-
(::Naf::QueuedJob.where(:
|
43
|
-
::Naf::RunningJob.where(:
|
63
|
+
(::Naf::QueuedJob.where(application_run_group_name: application_run_group_name).count +
|
64
|
+
::Naf::RunningJob.where(application_run_group_name: application_run_group_name).count) >= application_run_group_limit
|
44
65
|
else
|
45
66
|
logger.warn "not limited by run group restriction but don't know why: #{application_run_group_restriction.inspect}"
|
46
67
|
true
|
@@ -27,6 +27,7 @@ module Logical::Naf::ConstructionZone
|
|
27
27
|
|
28
28
|
def create_queued_job(historical_job)
|
29
29
|
queued_job = ::Naf::QueuedJob.new(application_id: historical_job.application_id,
|
30
|
+
application_schedule_id: historical_job.application_schedule_id,
|
30
31
|
application_type_id: historical_job.application_type_id,
|
31
32
|
command: historical_job.command,
|
32
33
|
application_run_group_restriction_id: historical_job.application_run_group_restriction_id,
|
@@ -1,8 +1,14 @@
|
|
1
1
|
module Logical::Naf::ConstructionZone
|
2
2
|
class WorkOrder
|
3
|
-
attr_reader :command,
|
4
|
-
|
5
|
-
|
3
|
+
attr_reader :command,
|
4
|
+
:application_type,
|
5
|
+
:application_run_group_restriction,
|
6
|
+
:application_run_group_name,
|
7
|
+
:application_run_group_limit,
|
8
|
+
:priority,
|
9
|
+
:enqueue_backlogs,
|
10
|
+
:application,
|
11
|
+
:application_schedule
|
6
12
|
|
7
13
|
def initialize(command,
|
8
14
|
application_type = ::Naf::ApplicationType.rails,
|
@@ -42,7 +48,8 @@ module Logical::Naf::ConstructionZone
|
|
42
48
|
application_run_group_name: application_run_group_name,
|
43
49
|
application_run_group_limit: application_run_group_limit,
|
44
50
|
priority: priority,
|
45
|
-
application_id: application.try(:id)
|
51
|
+
application_id: application.try(:id),
|
52
|
+
application_schedule_id: application_schedule.try(:id)
|
46
53
|
}
|
47
54
|
end
|
48
55
|
|
@@ -117,6 +117,7 @@ module Logical
|
|
117
117
|
if historical_job.present?
|
118
118
|
::Naf::QueuedJob.delete(historical_job.id)
|
119
119
|
running_job = ::Naf::RunningJob.new(application_id: historical_job.application_id,
|
120
|
+
application_schedule_id: historical_job.application_schedule_id,
|
120
121
|
application_type_id: historical_job.application_type_id,
|
121
122
|
command: historical_job.command,
|
122
123
|
application_run_group_restriction_id: historical_job.application_run_group_restriction_id,
|
@@ -7,8 +7,8 @@ module Naf
|
|
7
7
|
:log_level,
|
8
8
|
:short_name,
|
9
9
|
:deleted,
|
10
|
-
:
|
11
|
-
:
|
10
|
+
:application_schedules,
|
11
|
+
:application_schedules_attributes
|
12
12
|
|
13
13
|
#---------------------
|
14
14
|
# *** Associations ***
|
@@ -16,7 +16,7 @@ module Naf
|
|
16
16
|
|
17
17
|
belongs_to :application_type,
|
18
18
|
class_name: '::Naf::ApplicationType'
|
19
|
-
|
19
|
+
has_many :application_schedules,
|
20
20
|
class_name: '::Naf::ApplicationSchedule',
|
21
21
|
dependent: :destroy
|
22
22
|
has_many :historical_jobs,
|
@@ -35,12 +35,11 @@ module Naf
|
|
35
35
|
allow_nil: true,
|
36
36
|
format: {
|
37
37
|
with: /^[a-zA-Z_][a-zA-Z0-9_]*$/,
|
38
|
-
message: "letters
|
38
|
+
message: "short name consists of only letters/numbers/underscores, and it needs to start with a letter/underscore"
|
39
39
|
}
|
40
40
|
|
41
|
-
validate :check_references_with_application_schedule_prerequisites
|
42
41
|
before_save :check_blank_values
|
43
|
-
accepts_nested_attributes_for :
|
42
|
+
accepts_nested_attributes_for :application_schedules, allow_destroy: true
|
44
43
|
|
45
44
|
#--------------------
|
46
45
|
# *** Delegations ***
|
@@ -85,16 +84,6 @@ module Naf
|
|
85
84
|
self.log_level = nil if self.log_level.blank?
|
86
85
|
end
|
87
86
|
|
88
|
-
def check_references_with_application_schedule_prerequisites
|
89
|
-
if application_schedule.try(:marked_for_destruction?)
|
90
|
-
prerequisites = Naf::ApplicationSchedulePrerequisite.
|
91
|
-
where(prerequisite_application_schedule_id: application_schedule.id).all
|
92
|
-
unless prerequisites.blank?
|
93
|
-
errors.add(:base, "Cannot delete scheduler, because the following applications are referenced to it: " +
|
94
|
-
"#{prerequisites.map{ |pre| pre.application_schedule.title }.join(', ') }")
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
87
|
|
99
88
|
end
|
100
89
|
end
|
@@ -10,10 +10,14 @@ module Naf
|
|
10
10
|
:priority,
|
11
11
|
:visible,
|
12
12
|
:enabled,
|
13
|
-
:run_start_minute,
|
14
13
|
:application_run_group_limit,
|
14
|
+
:application_run_group_quantum,
|
15
15
|
:application_schedule_prerequisites_attributes,
|
16
|
-
:enqueue_backlogs
|
16
|
+
:enqueue_backlogs,
|
17
|
+
:run_interval_style_id,
|
18
|
+
:application,
|
19
|
+
:run_interval_style,
|
20
|
+
:application_run_group_restriction
|
17
21
|
|
18
22
|
SCHEDULES_LOCK_ID = 0
|
19
23
|
|
@@ -25,6 +29,8 @@ module Naf
|
|
25
29
|
class_name: '::Naf::Application'
|
26
30
|
belongs_to :application_run_group_restriction,
|
27
31
|
class_name: '::Naf::ApplicationRunGroupRestriction'
|
32
|
+
belongs_to :run_interval_style,
|
33
|
+
class_name: '::Naf::RunIntervalStyle'
|
28
34
|
has_many :application_schedule_affinity_tabs,
|
29
35
|
class_name: '::Naf::ApplicationScheduleAffinityTab',
|
30
36
|
dependent: :destroy
|
@@ -44,7 +50,10 @@ module Naf
|
|
44
50
|
# *** Validations ***
|
45
51
|
#++++++++++++++++++++
|
46
52
|
|
47
|
-
validates :application_run_group_restriction_id,
|
53
|
+
validates :application_run_group_restriction_id,
|
54
|
+
:run_interval_style_id,
|
55
|
+
:application_id,
|
56
|
+
:priority, presence: true
|
48
57
|
validates :priority, numericality: {
|
49
58
|
only_integer: true,
|
50
59
|
greater_than: -2147483648,
|
@@ -56,12 +65,6 @@ module Naf
|
|
56
65
|
less_than: 2147483647,
|
57
66
|
allow_blank: true
|
58
67
|
}
|
59
|
-
validates :run_start_minute, numericality: {
|
60
|
-
only_integer: true,
|
61
|
-
greater_than_or_equal_to: 0,
|
62
|
-
less_than: 24*60,
|
63
|
-
allow_blank: true
|
64
|
-
}
|
65
68
|
validates :run_interval, numericality: {
|
66
69
|
only_integer: true,
|
67
70
|
greater_than_or_equal_to: 0,
|
@@ -71,9 +74,8 @@ module Naf
|
|
71
74
|
|
72
75
|
before_save :check_blank_values
|
73
76
|
validate :visible_enabled_check
|
74
|
-
validate :run_interval_at_time_check
|
75
|
-
validate :enabled_application_id_unique
|
76
77
|
validate :prerequisite_application_schedule_id_uniqueness
|
78
|
+
validate :run_interval_check
|
77
79
|
|
78
80
|
#--------------------
|
79
81
|
# *** Delegations ***
|
@@ -94,17 +96,102 @@ module Naf
|
|
94
96
|
unlock_record(SCHEDULES_LOCK_ID)
|
95
97
|
end
|
96
98
|
|
97
|
-
|
98
|
-
|
99
|
+
# find the exact based schedules that should be queued
|
100
|
+
# select anything that
|
101
|
+
# isn't currently running (or queued) AND
|
102
|
+
# hasn't run since run_interval AND
|
103
|
+
# should have been run by now
|
104
|
+
def self.exact_schedules(time, not_finished_applications, application_last_runs)
|
105
|
+
custom_current_time = time.to_date + time.strftime('%H').to_i.hours + time.strftime('%M').to_i.minutes
|
106
|
+
schedules = ::Naf::ApplicationSchedule.
|
107
|
+
joins(:run_interval_style).
|
108
|
+
where("#{Naf.schema_name}.run_interval_styles.name IN (?)", ['at beginning of day', 'at beginning of hour']).
|
109
|
+
enabled.select do |schedule|
|
110
|
+
|
111
|
+
interval_time = time.to_date
|
112
|
+
if schedule.run_interval_style.name == 'at beginning of day'
|
113
|
+
interval_time += schedule.run_interval.minutes
|
114
|
+
elsif schedule.run_interval_style.name == 'at beginning of hour'
|
115
|
+
interval_time += time.strftime('%H').to_i.hours + schedule.run_interval.minutes
|
116
|
+
end
|
117
|
+
|
118
|
+
(not_finished_applications[schedule.id].nil? &&
|
119
|
+
(application_last_runs[schedule.id].nil? ||
|
120
|
+
(interval_time >= application_last_runs[schedule.id].finished_at)
|
121
|
+
) &&
|
122
|
+
(custom_current_time - interval_time) == 0.seconds
|
123
|
+
)
|
124
|
+
end
|
125
|
+
|
126
|
+
schedules
|
99
127
|
end
|
100
128
|
|
101
|
-
|
102
|
-
|
129
|
+
# find the interval based schedules that should be queued
|
130
|
+
# select anything that isn't currently running and completed
|
131
|
+
# running more than run_interval minutes ago
|
132
|
+
def self.relative_schedules(time, not_finished_applications, application_last_runs)
|
133
|
+
schedules = ::Naf::ApplicationSchedule.
|
134
|
+
joins(:run_interval_style).
|
135
|
+
where("#{Naf.schema_name}.run_interval_styles.name = ?", 'after previous run').
|
136
|
+
enabled.select do |schedule|
|
137
|
+
|
138
|
+
(not_finished_applications[schedule.id].nil? &&
|
139
|
+
(application_last_runs[schedule.id].nil? ||
|
140
|
+
(time - application_last_runs[schedule.id].finished_at) > schedule.run_interval.minutes
|
141
|
+
)
|
142
|
+
)
|
143
|
+
end
|
144
|
+
|
145
|
+
schedules
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.constant_schedules
|
149
|
+
::Naf::ApplicationSchedule.
|
150
|
+
joins(:run_interval_style).
|
151
|
+
where("#{Naf.schema_name}.run_interval_styles.name = ?", 'keep running').
|
152
|
+
enabled
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.enabled
|
156
|
+
where(enabled: true)
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.should_be_queued
|
160
|
+
current_time = Time.zone.now
|
161
|
+
# Applications that are still running
|
162
|
+
not_finished_applications = ::Naf::HistoricalJob.
|
163
|
+
queued_between(current_time - Naf::HistoricalJob::JOB_STALE_TIME, current_time).
|
164
|
+
where("finished_at IS NULL AND request_to_terminate = false").
|
165
|
+
find_all{ |job| job.application_schedule_id.present? }.
|
166
|
+
index_by{ |job| job.application_schedule_id }
|
167
|
+
|
168
|
+
# Last ran job for each application
|
169
|
+
application_last_runs = ::Naf::HistoricalJob.application_last_runs.
|
170
|
+
index_by{ |job| job.application_schedule_id }
|
171
|
+
|
172
|
+
relative_schedules = ::Naf::ApplicationSchedule.
|
173
|
+
relative_schedules(current_time, not_finished_applications, application_last_runs)
|
174
|
+
exact_schedules = ::Naf::ApplicationSchedule.
|
175
|
+
exact_schedules(current_time, not_finished_applications, application_last_runs)
|
176
|
+
constant_schedules = ::Naf::ApplicationSchedule.constant_schedules
|
177
|
+
|
178
|
+
foreman = ::Logical::Naf::ConstructionZone::Foreman.new
|
179
|
+
return (relative_schedules + exact_schedules + constant_schedules).select do |schedule|
|
180
|
+
affinities = []
|
181
|
+
schedule.affinities.each do |affinity|
|
182
|
+
affinities << { affinity_id: affinity.id }
|
183
|
+
end
|
184
|
+
|
185
|
+
schedule.enqueue_backlogs || !foreman.limited_by_run_group?(schedule.application_run_group_restriction,
|
186
|
+
schedule.application_run_group_name,
|
187
|
+
schedule.application_run_group_limit,
|
188
|
+
affinities)
|
189
|
+
end
|
103
190
|
end
|
104
191
|
|
105
|
-
def self.
|
192
|
+
def self.pickleables
|
106
193
|
# check the application is deleted
|
107
|
-
self.where(:
|
194
|
+
self.where(deleted: false)
|
108
195
|
end
|
109
196
|
|
110
197
|
#-------------------------
|
@@ -124,11 +211,7 @@ module Naf
|
|
124
211
|
end
|
125
212
|
components << "id: #{id}"
|
126
213
|
components << "\"#{application.title}\""
|
127
|
-
|
128
|
-
components << "start at: #{"%02d" % (run_start_minute/60)}:#{"%02d" % (run_start_minute%60)}"
|
129
|
-
else
|
130
|
-
components << "start every: #{run_interval} minutes"
|
131
|
-
end
|
214
|
+
components << ::Logical::Naf::ApplicationSchedule.new(self).display
|
132
215
|
|
133
216
|
return "::Naf::ApplicationSchedule<#{components.join(', ')}>"
|
134
217
|
end
|
@@ -140,31 +223,22 @@ module Naf
|
|
140
223
|
end
|
141
224
|
end
|
142
225
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
226
|
+
# When rolling back from Naf v2.1 to v2.0, check whether run_interval
|
227
|
+
# or run_start_minute is nil. Otherwise, just check the presence of
|
228
|
+
# run_interval.
|
229
|
+
def run_interval_check
|
230
|
+
if self.attributes.keys.include?('run_start_minute')
|
231
|
+
if !run_start_minute.present? && !run_interval.present?
|
232
|
+
errors.add(:run_interval, "or run_start_minute must be nil")
|
233
|
+
errors.add(:run_start_minute, "or run_interval must be nil")
|
234
|
+
end
|
148
235
|
else
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
num_collisions = self.class.count(conditions: conditions)
|
153
|
-
errors.add(:application_id, "is enabled and has already been taken") if num_collisions > 0
|
154
|
-
end
|
155
|
-
|
156
|
-
def run_interval_at_time_check
|
157
|
-
unless (run_start_minute.blank? || run_interval.blank?)
|
158
|
-
errors.add(:run_interval, "or Run start minute must be nil")
|
159
|
-
errors.add(:run_start_minute, "or Run interval must be nil")
|
236
|
+
if !run_interval.present?
|
237
|
+
errors.add(:run_interval, "must be present")
|
238
|
+
end
|
160
239
|
end
|
161
240
|
end
|
162
241
|
|
163
|
-
def self.pickleables(pickler)
|
164
|
-
self.joins(:application).
|
165
|
-
where("#{::Naf.schema_name}.applications.deleted IS FALSE")
|
166
|
-
end
|
167
|
-
|
168
242
|
private
|
169
243
|
|
170
244
|
def prerequisite_application_schedule_id_uniqueness
|
@@ -15,6 +15,7 @@ module Naf
|
|
15
15
|
|
16
16
|
# Protect from mass-assignment issue
|
17
17
|
attr_accessible :application_id,
|
18
|
+
:application_schedule_id,
|
18
19
|
:application_type_id,
|
19
20
|
:command,
|
20
21
|
:application_run_group_restriction_id,
|
@@ -44,6 +45,8 @@ module Naf
|
|
44
45
|
# *** Associations ***
|
45
46
|
#+++++++++++++++++++++
|
46
47
|
|
48
|
+
belongs_to :application_schedule,
|
49
|
+
class_name: '::Naf::ApplicationSchedule'
|
47
50
|
belongs_to :application_type,
|
48
51
|
class_name: '::Naf::ApplicationType'
|
49
52
|
belongs_to :started_on_machine,
|
@@ -175,9 +178,9 @@ module Naf
|
|
175
178
|
end
|
176
179
|
|
177
180
|
def self.application_last_runs
|
178
|
-
where("
|
179
|
-
group("
|
180
|
-
select("
|
181
|
+
where("application_schedule_id IS NOT NULL").
|
182
|
+
group("application_schedule_id").
|
183
|
+
select("application_schedule_id, MAX(finished_at) AS finished_at").
|
181
184
|
reject{ |job| job.finished_at.nil? }
|
182
185
|
end
|
183
186
|
|