maintenance_tasks 1.6.0 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +23 -8
- data/app/controllers/maintenance_tasks/tasks_controller.rb +2 -1
- data/app/helpers/maintenance_tasks/tasks_helper.rb +19 -0
- data/app/jobs/concerns/maintenance_tasks/task_job_concern.rb +16 -30
- data/app/models/maintenance_tasks/csv_collection_builder.rb +4 -3
- data/app/models/maintenance_tasks/run.rb +130 -14
- data/app/models/maintenance_tasks/task.rb +11 -5
- data/app/models/maintenance_tasks/task_data.rb +12 -1
- data/app/views/maintenance_tasks/runs/_run.html.erb +4 -0
- data/app/views/maintenance_tasks/runs/info/_custom.html.erb +0 -0
- data/app/views/maintenance_tasks/tasks/_custom.html.erb +0 -0
- data/app/views/maintenance_tasks/tasks/_task.html.erb +4 -0
- data/app/views/maintenance_tasks/tasks/show.html.erb +11 -5
- data/db/migrate/20211210152329_add_lock_version_to_maintenance_tasks_runs.rb +8 -0
- data/lib/maintenance_tasks/engine.rb +10 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6019b1623a8cc72e877154f52e8437339598f0cab121189d78692e0989e86e61
|
4
|
+
data.tar.gz: 21563dc6dffadd2e58dd551fe2b7d71297b2da36500722f5d9fed91892b1fd6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 93228d08b49fab144297cb44a0aa4b9be53144ff13b88c2eba384ef29fdb47b9a8caefaf94aaf1fbfbf4584f4d544396720c17d86f3bad31508fd66dfd7507b8
|
7
|
+
data.tar.gz: cab4cebb685fddf978eeebd62a5c16867215f849d424b9ba948beba0e93f42a5fe11ee1eccc15174c1494fa16a2fa100d3a7745c5eacef2527d425895805cf29
|
data/README.md
CHANGED
@@ -114,8 +114,9 @@ title,content
|
|
114
114
|
My Title,Hello World!
|
115
115
|
```
|
116
116
|
|
117
|
-
The files uploaded to your Active Storage service provider will be renamed
|
117
|
+
The files uploaded to your Active Storage service provider will be renamed
|
118
118
|
to include an ISO8601 timestamp and the Task name in snake case format.
|
119
|
+
The CSV is expected to have a trailing newline at the end of the file.
|
119
120
|
|
120
121
|
### Processing Batch Collections
|
121
122
|
|
@@ -200,6 +201,20 @@ Tasks can define multiple throttle conditions. Throttle conditions are inherited
|
|
200
201
|
by descendants, and new conditions will be appended without impacting existing
|
201
202
|
conditions.
|
202
203
|
|
204
|
+
The backoff can also be specified as a proc:
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
# app/tasks/maintenance/update_posts_throttled_task.rb
|
208
|
+
|
209
|
+
module Maintenance
|
210
|
+
class UpdatePostsThrottledTask < MaintenanceTasks::Task
|
211
|
+
throttle_on(backoff: -> { RandomBackoffGenerator.generate_duration } ) do
|
212
|
+
DatabaseStatus.unhealthy?
|
213
|
+
end
|
214
|
+
...
|
215
|
+
end
|
216
|
+
end
|
217
|
+
```
|
203
218
|
### Custom Task Parameters
|
204
219
|
|
205
220
|
Tasks may need additional information, supplied via parameters, to run.
|
@@ -241,12 +256,12 @@ The Task provides callbacks that hook into its life cycle.
|
|
241
256
|
|
242
257
|
Available callbacks are:
|
243
258
|
|
244
|
-
`after_start`
|
245
|
-
`after_pause`
|
246
|
-
`after_interrupt`
|
247
|
-
`after_cancel`
|
248
|
-
`after_complete`
|
249
|
-
`after_error`
|
259
|
+
* `after_start`
|
260
|
+
* `after_pause`
|
261
|
+
* `after_interrupt`
|
262
|
+
* `after_cancel`
|
263
|
+
* `after_complete`
|
264
|
+
* `after_error`
|
250
265
|
|
251
266
|
```ruby
|
252
267
|
module Maintenance
|
@@ -542,7 +557,7 @@ you can define an error handler:
|
|
542
557
|
|
543
558
|
MaintenanceTasks.error_handler = ->(error, task_context, _errored_element) do
|
544
559
|
Bugsnag.notify(error) do |notification|
|
545
|
-
notification.
|
560
|
+
notification.add_metadata(:task, task_context)
|
546
561
|
end
|
547
562
|
end
|
548
563
|
```
|
@@ -24,11 +24,12 @@ module MaintenanceTasks
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# Runs a given Task and redirects to the Task page.
|
27
|
-
def run
|
27
|
+
def run(&block)
|
28
28
|
task = Runner.run(
|
29
29
|
name: params.fetch(:id),
|
30
30
|
csv_file: params[:csv_file],
|
31
31
|
arguments: params.fetch(:task_arguments, {}).permit!.to_h,
|
32
|
+
&block
|
32
33
|
)
|
33
34
|
redirect_to(task_path(task))
|
34
35
|
rescue ActiveRecord::RecordInvalid => error
|
@@ -100,5 +100,24 @@ module MaintenanceTasks
|
|
100
100
|
only_path: true
|
101
101
|
)
|
102
102
|
end
|
103
|
+
|
104
|
+
# Return the appropriate field tag for the parameter
|
105
|
+
def parameter_field(form_builder, parameter_name)
|
106
|
+
case form_builder.object.class.attribute_types[parameter_name]
|
107
|
+
when ActiveModel::Type::Integer, ActiveModel::Type::Decimal,
|
108
|
+
ActiveModel::Type::Float
|
109
|
+
form_builder.number_field(parameter_name)
|
110
|
+
when ActiveModel::Type::DateTime
|
111
|
+
form_builder.datetime_field(parameter_name)
|
112
|
+
when ActiveModel::Type::Date
|
113
|
+
form_builder.date_field(parameter_name)
|
114
|
+
when ActiveModel::Type::Time
|
115
|
+
form_builder.time_field(parameter_name)
|
116
|
+
when ActiveModel::Type::Boolean
|
117
|
+
form_builder.check_box(parameter_name)
|
118
|
+
else
|
119
|
+
form_builder.text_area(parameter_name, class: "textarea")
|
120
|
+
end
|
121
|
+
end
|
103
122
|
end
|
104
123
|
end
|
@@ -12,8 +12,8 @@ module MaintenanceTasks
|
|
12
12
|
before_perform(:before_perform)
|
13
13
|
|
14
14
|
on_start(:on_start)
|
15
|
-
on_complete(:on_complete)
|
16
15
|
on_shutdown(:on_shutdown)
|
16
|
+
on_complete(:on_complete)
|
17
17
|
|
18
18
|
after_perform(:after_perform)
|
19
19
|
|
@@ -63,9 +63,16 @@ module MaintenanceTasks
|
|
63
63
|
Array, or CSV.
|
64
64
|
MSG
|
65
65
|
end
|
66
|
+
throttle_enumerator(collection_enum)
|
67
|
+
end
|
66
68
|
|
69
|
+
def throttle_enumerator(collection_enum)
|
67
70
|
@task.throttle_conditions.reduce(collection_enum) do |enum, condition|
|
68
|
-
enumerator_builder.build_throttle_enumerator(
|
71
|
+
enumerator_builder.build_throttle_enumerator(
|
72
|
+
enum,
|
73
|
+
throttle_on: condition[:throttle_on],
|
74
|
+
backoff: condition[:backoff].call
|
75
|
+
)
|
69
76
|
end
|
70
77
|
end
|
71
78
|
|
@@ -105,33 +112,19 @@ module MaintenanceTasks
|
|
105
112
|
def on_start
|
106
113
|
count = @task.count
|
107
114
|
count = @enumerator&.size if count == :no_count
|
108
|
-
@run.
|
109
|
-
@task.run_callbacks(:start)
|
110
|
-
end
|
111
|
-
|
112
|
-
def on_complete
|
113
|
-
@run.status = :succeeded
|
114
|
-
@run.ended_at = Time.now
|
115
|
-
@task.run_callbacks(:complete)
|
115
|
+
@run.start(count)
|
116
116
|
end
|
117
117
|
|
118
118
|
def on_shutdown
|
119
|
-
|
120
|
-
@run.status = :cancelled
|
121
|
-
@task.run_callbacks(:cancel)
|
122
|
-
@run.ended_at = Time.now
|
123
|
-
elsif @run.pausing?
|
124
|
-
@run.status = :paused
|
125
|
-
@task.run_callbacks(:pause)
|
126
|
-
else
|
127
|
-
@run.status = :interrupted
|
128
|
-
@task.run_callbacks(:interrupt)
|
129
|
-
end
|
130
|
-
|
119
|
+
@run.job_shutdown
|
131
120
|
@run.cursor = cursor_position
|
132
121
|
@ticker.persist
|
133
122
|
end
|
134
123
|
|
124
|
+
def on_complete
|
125
|
+
@run.complete
|
126
|
+
end
|
127
|
+
|
135
128
|
# We are reopening a private part of Job Iteration's API here, so we should
|
136
129
|
# ensure the method is still defined upstream. This way, in the case where
|
137
130
|
# the method changes upstream, we catch it at load time instead of at
|
@@ -150,7 +143,7 @@ module MaintenanceTasks
|
|
150
143
|
end
|
151
144
|
|
152
145
|
def after_perform
|
153
|
-
@run.
|
146
|
+
@run.persist_transition
|
154
147
|
if defined?(@reenqueue_iteration_job) && @reenqueue_iteration_job
|
155
148
|
reenqueue_iteration_job(should_ignore: false)
|
156
149
|
end
|
@@ -171,15 +164,8 @@ module MaintenanceTasks
|
|
171
164
|
task_context = {}
|
172
165
|
end
|
173
166
|
errored_element = @errored_element if defined?(@errored_element)
|
174
|
-
run_error_callback
|
175
167
|
ensure
|
176
168
|
MaintenanceTasks.error_handler.call(error, task_context, errored_element)
|
177
169
|
end
|
178
|
-
|
179
|
-
def run_error_callback
|
180
|
-
@task.run_callbacks(:error) if defined?(@task)
|
181
|
-
rescue
|
182
|
-
nil
|
183
|
-
end
|
184
170
|
end
|
185
171
|
end
|
@@ -15,9 +15,10 @@ module MaintenanceTasks
|
|
15
15
|
CSV.new(task.csv_content, headers: true)
|
16
16
|
end
|
17
17
|
|
18
|
-
# The number of rows to be processed. Excludes the header row from the
|
19
|
-
# and
|
20
|
-
# an approximation based on the number of
|
18
|
+
# The number of rows to be processed. Excludes the header row from the
|
19
|
+
# count and assumes a trailing newline is at the end of the CSV file.
|
20
|
+
# Note that this number is an approximation based on the number of
|
21
|
+
# newlines.
|
21
22
|
#
|
22
23
|
# @return [Integer] the approximate number of rows to process.
|
23
24
|
def count(task)
|
@@ -66,9 +66,40 @@ module MaintenanceTasks
|
|
66
66
|
|
67
67
|
# Sets the run status to enqueued, making sure the transition is validated
|
68
68
|
# in case it's already enqueued.
|
69
|
+
#
|
70
|
+
# Rescues and retries status transition if an ActiveRecord::StaleObjectError
|
71
|
+
# is encountered.
|
69
72
|
def enqueued!
|
70
73
|
status_will_change!
|
71
74
|
super
|
75
|
+
rescue ActiveRecord::StaleObjectError
|
76
|
+
reload_status
|
77
|
+
retry
|
78
|
+
end
|
79
|
+
|
80
|
+
CALLBACKS_TRANSITION = {
|
81
|
+
cancelled: :cancel,
|
82
|
+
interrupted: :interrupt,
|
83
|
+
paused: :pause,
|
84
|
+
succeeded: :complete,
|
85
|
+
}.transform_keys(&:to_s)
|
86
|
+
private_constant :CALLBACKS_TRANSITION
|
87
|
+
|
88
|
+
# Saves the run, persisting the transition of its status, and all other
|
89
|
+
# changes to the object.
|
90
|
+
def persist_transition
|
91
|
+
save!
|
92
|
+
callback = CALLBACKS_TRANSITION[status]
|
93
|
+
run_task_callbacks(callback) if callback
|
94
|
+
rescue ActiveRecord::StaleObjectError
|
95
|
+
success = succeeded?
|
96
|
+
reload_status
|
97
|
+
if success
|
98
|
+
self.status = :succeeded
|
99
|
+
else
|
100
|
+
job_shutdown
|
101
|
+
end
|
102
|
+
retry
|
72
103
|
end
|
73
104
|
|
74
105
|
# Increments +tick_count+ by +number_of_ticks+ and +time_running+ by
|
@@ -86,6 +117,11 @@ module MaintenanceTasks
|
|
86
117
|
time_running: duration,
|
87
118
|
touch: true
|
88
119
|
)
|
120
|
+
if locking_enabled?
|
121
|
+
locking_column = self.class.locking_column
|
122
|
+
self[locking_column] += 1
|
123
|
+
clear_attribute_change(locking_column)
|
124
|
+
end
|
89
125
|
end
|
90
126
|
|
91
127
|
# Marks the run as errored and persists the error data.
|
@@ -100,20 +136,34 @@ module MaintenanceTasks
|
|
100
136
|
backtrace: MaintenanceTasks.backtrace_cleaner.clean(error.backtrace),
|
101
137
|
ended_at: Time.now,
|
102
138
|
)
|
139
|
+
run_task_callbacks(:error)
|
140
|
+
rescue ActiveRecord::StaleObjectError
|
141
|
+
reload_status
|
142
|
+
retry
|
103
143
|
end
|
104
144
|
|
105
|
-
# Refreshes
|
106
|
-
# ensures ActiveModel::Dirty
|
145
|
+
# Refreshes the status and lock version attributes on the Active Record
|
146
|
+
# object, and ensures ActiveModel::Dirty doesn't mark the object as changed.
|
147
|
+
#
|
107
148
|
# This allows us to get the Run's most up-to-date status without needing
|
108
149
|
# to reload the entire record.
|
109
150
|
#
|
110
151
|
# @return [MaintenanceTasks::Run] the Run record with its updated status.
|
111
152
|
def reload_status
|
112
|
-
|
113
|
-
self.class.
|
153
|
+
columns_to_reload = if locking_enabled?
|
154
|
+
[:status, self.class.locking_column]
|
155
|
+
else
|
156
|
+
[:status]
|
157
|
+
end
|
158
|
+
updated_status, updated_lock_version = self.class.uncached do
|
159
|
+
self.class.where(id: id).pluck(*columns_to_reload).first
|
114
160
|
end
|
161
|
+
|
115
162
|
self.status = updated_status
|
116
|
-
|
163
|
+
if updated_lock_version
|
164
|
+
self[self.class.locking_column] = updated_lock_version
|
165
|
+
end
|
166
|
+
clear_attribute_changes(columns_to_reload)
|
117
167
|
self
|
118
168
|
end
|
119
169
|
|
@@ -173,21 +223,65 @@ module MaintenanceTasks
|
|
173
223
|
seconds_to_finished.seconds
|
174
224
|
end
|
175
225
|
|
176
|
-
#
|
226
|
+
# Marks a Run as running.
|
177
227
|
#
|
178
228
|
# If the run is stopping already, it will not transition to running.
|
229
|
+
# Rescues and retries status transition if an ActiveRecord::StaleObjectError
|
230
|
+
# is encountered.
|
179
231
|
def running
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
232
|
+
if locking_enabled?
|
233
|
+
begin
|
234
|
+
running! unless stopping?
|
235
|
+
rescue ActiveRecord::StaleObjectError
|
236
|
+
reload_status
|
237
|
+
retry
|
238
|
+
end
|
239
|
+
else
|
240
|
+
# Preserve swap-and-replace solution for data races until users
|
241
|
+
# run migration to upgrade to optimistic locking solution
|
242
|
+
return if stopping?
|
243
|
+
updated = self.class.where(id: id).where.not(status: STOPPING_STATUSES)
|
244
|
+
.update_all(status: :running, updated_at: Time.now) > 0
|
245
|
+
if updated
|
246
|
+
self.status = :running
|
247
|
+
clear_attribute_changes([:status])
|
248
|
+
else
|
249
|
+
reload_status
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# Starts a Run, setting its started_at timestamp and tick_total.
|
255
|
+
#
|
256
|
+
# @param count [Integer] the total iterations to be performed, as
|
257
|
+
# specified by the Task.
|
258
|
+
def start(count)
|
259
|
+
update!(started_at: Time.now, tick_total: count)
|
260
|
+
run_task_callbacks(:start)
|
261
|
+
rescue ActiveRecord::StaleObjectError
|
262
|
+
reload_status
|
263
|
+
retry
|
264
|
+
end
|
265
|
+
|
266
|
+
# Handles transitioning the status on a Run when the job shuts down.
|
267
|
+
def job_shutdown
|
268
|
+
if cancelling?
|
269
|
+
self.status = :cancelled
|
270
|
+
self.ended_at = Time.now
|
271
|
+
elsif pausing?
|
272
|
+
self.status = :paused
|
186
273
|
else
|
187
|
-
|
274
|
+
self.status = :interrupted
|
188
275
|
end
|
189
276
|
end
|
190
277
|
|
278
|
+
# Handles the completion of a Run, setting a status of succeeded and the
|
279
|
+
# ended_at timestamp.
|
280
|
+
def complete
|
281
|
+
self.status = :succeeded
|
282
|
+
self.ended_at = Time.now
|
283
|
+
end
|
284
|
+
|
191
285
|
# Cancels a Run.
|
192
286
|
#
|
193
287
|
# If the Run is paused, it will transition directly to cancelled, since the
|
@@ -201,10 +295,26 @@ module MaintenanceTasks
|
|
201
295
|
# will be updated.
|
202
296
|
def cancel
|
203
297
|
if paused? || stuck?
|
204
|
-
|
298
|
+
self.status = :cancelled
|
299
|
+
self.ended_at = Time.now
|
300
|
+
persist_transition
|
205
301
|
else
|
206
302
|
cancelling!
|
207
303
|
end
|
304
|
+
rescue ActiveRecord::StaleObjectError
|
305
|
+
reload_status
|
306
|
+
retry
|
307
|
+
end
|
308
|
+
|
309
|
+
# Marks a Run as pausing.
|
310
|
+
#
|
311
|
+
# Rescues and retries status transition if an ActiveRecord::StaleObjectError
|
312
|
+
# is encountered.
|
313
|
+
def pausing!
|
314
|
+
super
|
315
|
+
rescue ActiveRecord::StaleObjectError
|
316
|
+
reload_status
|
317
|
+
retry
|
208
318
|
end
|
209
319
|
|
210
320
|
# Returns whether a Run is stuck, which is defined as having a status of
|
@@ -297,6 +407,12 @@ module MaintenanceTasks
|
|
297
407
|
|
298
408
|
private
|
299
409
|
|
410
|
+
def run_task_callbacks(callback)
|
411
|
+
task.run_callbacks(callback)
|
412
|
+
rescue
|
413
|
+
nil
|
414
|
+
end
|
415
|
+
|
300
416
|
def arguments_match_task_attributes
|
301
417
|
invalid_argument_keys = arguments.keys - task.attribute_names
|
302
418
|
if invalid_argument_keys.any?
|
@@ -59,7 +59,8 @@ module MaintenanceTasks
|
|
59
59
|
"To resolve this issue run: bin/rails active_storage:install"
|
60
60
|
end
|
61
61
|
|
62
|
-
self.collection_builder_strategy =
|
62
|
+
self.collection_builder_strategy =
|
63
|
+
MaintenanceTasks::CsvCollectionBuilder.new
|
63
64
|
end
|
64
65
|
|
65
66
|
# Returns whether the Task handles CSV.
|
@@ -98,14 +99,19 @@ module MaintenanceTasks
|
|
98
99
|
|
99
100
|
# Add a condition under which this Task will be throttled.
|
100
101
|
#
|
101
|
-
# @param backoff [ActiveSupport::Duration]
|
102
|
-
# can be specified. This is the time to wait before retrying the Task
|
103
|
-
# If
|
102
|
+
# @param backoff [ActiveSupport::Duration, #call] a custom backoff
|
103
|
+
# can be specified. This is the time to wait before retrying the Task,
|
104
|
+
# defaulting to 30 seconds. If provided as a Duration, the backoff is
|
105
|
+
# wrapped in a proc. Alternatively,an object responding to call can be
|
106
|
+
# used. It must return an ActiveSupport::Duration.
|
104
107
|
# @yieldreturn [Boolean] where the throttle condition is being met,
|
105
108
|
# indicating that the Task should throttle.
|
106
109
|
def throttle_on(backoff: 30.seconds, &condition)
|
110
|
+
backoff_as_proc = backoff
|
111
|
+
backoff_as_proc = -> { backoff } unless backoff.respond_to?(:call)
|
112
|
+
|
107
113
|
self.throttle_conditions += [
|
108
|
-
{ throttle_on: condition, backoff:
|
114
|
+
{ throttle_on: condition, backoff: backoff_as_proc },
|
109
115
|
]
|
110
116
|
end
|
111
117
|
|
@@ -74,7 +74,11 @@ module MaintenanceTasks
|
|
74
74
|
def code
|
75
75
|
return if deleted?
|
76
76
|
task = Task.named(name)
|
77
|
-
file =
|
77
|
+
file = if Object.respond_to?(:const_source_location)
|
78
|
+
Object.const_source_location(task.name).first
|
79
|
+
else
|
80
|
+
task.instance_method(:process).source_location.first
|
81
|
+
end
|
78
82
|
File.read(file)
|
79
83
|
end
|
80
84
|
|
@@ -142,6 +146,13 @@ module MaintenanceTasks
|
|
142
146
|
end
|
143
147
|
end
|
144
148
|
|
149
|
+
# @return [MaintenanceTasks::Task, nil] an instance of the Task class.
|
150
|
+
# @return [nil] if the Task file was deleted.
|
151
|
+
def new
|
152
|
+
return if deleted?
|
153
|
+
MaintenanceTasks::Task.named(name).new
|
154
|
+
end
|
155
|
+
|
145
156
|
private
|
146
157
|
|
147
158
|
def runs
|
@@ -10,6 +10,10 @@
|
|
10
10
|
<%= render "maintenance_tasks/runs/info/#{run.status}", run: run %>
|
11
11
|
</div>
|
12
12
|
|
13
|
+
<div class="content" id="custom-content">
|
14
|
+
<%= render "maintenance_tasks/runs/info/custom", run: run %>
|
15
|
+
</div>
|
16
|
+
|
13
17
|
<%= render "maintenance_tasks/runs/csv", run: run %>
|
14
18
|
<%= tag.hr if run.csv_file.present? && run.arguments.present? %>
|
15
19
|
<%= render "maintenance_tasks/runs/arguments", run: run %>
|
File without changes
|
File without changes
|
@@ -15,6 +15,10 @@
|
|
15
15
|
<%= render "maintenance_tasks/runs/info/#{run.status}", run: run %>
|
16
16
|
</div>
|
17
17
|
|
18
|
+
<div class="content" id="custom-content">
|
19
|
+
<%= render "maintenance_tasks/runs/info/custom", run: run %>
|
20
|
+
</div>
|
21
|
+
|
18
22
|
<%= render "maintenance_tasks/runs/csv", run: run %>
|
19
23
|
<%= tag.hr if run.csv_file.present? && run.arguments.present? %>
|
20
24
|
<%= render "maintenance_tasks/runs/arguments", run: run %>
|
@@ -16,6 +16,10 @@
|
|
16
16
|
<%= render "maintenance_tasks/runs/info/#{last_run.status}", run: last_run %>
|
17
17
|
</div>
|
18
18
|
|
19
|
+
<div class="content" id="custom-content">
|
20
|
+
<%= render "maintenance_tasks/runs/info/custom", run: last_run %>
|
21
|
+
</div>
|
22
|
+
|
19
23
|
<%= render "maintenance_tasks/runs/csv", run: last_run %>
|
20
24
|
<%= tag.hr if last_run.csv_file.present? %>
|
21
25
|
<%= render "maintenance_tasks/runs/arguments", run: last_run %>
|
@@ -31,20 +35,22 @@
|
|
31
35
|
<%= form.file_field :csv_file %>
|
32
36
|
</div>
|
33
37
|
<% end %>
|
34
|
-
<%
|
38
|
+
<% parameter_names = @task.parameter_names %>
|
39
|
+
<% if parameter_names.any? %>
|
35
40
|
<div class="block">
|
36
|
-
<%= form.fields_for :task_arguments do |ff| %>
|
37
|
-
<%
|
41
|
+
<%= form.fields_for :task_arguments, @task.new do |ff| %>
|
42
|
+
<% parameter_names.each do |parameter_name| %>
|
38
43
|
<div class="field">
|
39
|
-
<%= ff.label
|
44
|
+
<%= ff.label parameter_name, parameter_name, class: "label is-family-monospace" %>
|
40
45
|
<div class="control">
|
41
|
-
<%= ff
|
46
|
+
<%= parameter_field(ff, parameter_name) %>
|
42
47
|
</div>
|
43
48
|
</div>
|
44
49
|
<% end %>
|
45
50
|
<% end %>
|
46
51
|
</div>
|
47
52
|
<% end %>
|
53
|
+
<%= render "maintenance_tasks/tasks/custom", form: form %>
|
48
54
|
<div class="block">
|
49
55
|
<%= form.submit 'Run', class: "button is-success", disabled: @task.deleted? %>
|
50
56
|
</div>
|
@@ -8,7 +8,16 @@ module MaintenanceTasks
|
|
8
8
|
class Engine < ::Rails::Engine
|
9
9
|
isolate_namespace MaintenanceTasks
|
10
10
|
|
11
|
-
initializer "
|
11
|
+
initializer "maintenance_tasks.warn_classic_autoloader" do
|
12
|
+
unless Rails.autoloaders.zeitwerk_enabled?
|
13
|
+
ActiveSupport::Deprecation.warn(<<~MSG.squish)
|
14
|
+
Autoloading in classic mode is deprecated and support will be removed in the next
|
15
|
+
release of Maintenance Tasks. Please use Zeitwerk to autoload your application.
|
16
|
+
MSG
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
initializer "maintenance_tasks.eager_load_for_classic_autoloader" do
|
12
21
|
eager_load! unless Rails.autoloaders.zeitwerk_enabled?
|
13
22
|
end
|
14
23
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: maintenance_tasks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify Engineering
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -114,6 +114,7 @@ files:
|
|
114
114
|
- app/views/maintenance_tasks/runs/_run.html.erb
|
115
115
|
- app/views/maintenance_tasks/runs/info/_cancelled.html.erb
|
116
116
|
- app/views/maintenance_tasks/runs/info/_cancelling.html.erb
|
117
|
+
- app/views/maintenance_tasks/runs/info/_custom.html.erb
|
117
118
|
- app/views/maintenance_tasks/runs/info/_enqueued.html.erb
|
118
119
|
- app/views/maintenance_tasks/runs/info/_errored.html.erb
|
119
120
|
- app/views/maintenance_tasks/runs/info/_interrupted.html.erb
|
@@ -121,6 +122,7 @@ files:
|
|
121
122
|
- app/views/maintenance_tasks/runs/info/_pausing.html.erb
|
122
123
|
- app/views/maintenance_tasks/runs/info/_running.html.erb
|
123
124
|
- app/views/maintenance_tasks/runs/info/_succeeded.html.erb
|
125
|
+
- app/views/maintenance_tasks/tasks/_custom.html.erb
|
124
126
|
- app/views/maintenance_tasks/tasks/_task.html.erb
|
125
127
|
- app/views/maintenance_tasks/tasks/index.html.erb
|
126
128
|
- app/views/maintenance_tasks/tasks/show.html.erb
|
@@ -128,6 +130,7 @@ files:
|
|
128
130
|
- db/migrate/20201211151756_create_maintenance_tasks_runs.rb
|
129
131
|
- db/migrate/20210225152418_remove_index_on_task_name.rb
|
130
132
|
- db/migrate/20210517131953_add_arguments_to_maintenance_tasks_runs.rb
|
133
|
+
- db/migrate/20211210152329_add_lock_version_to_maintenance_tasks_runs.rb
|
131
134
|
- exe/maintenance_tasks
|
132
135
|
- lib/generators/maintenance_tasks/install_generator.rb
|
133
136
|
- lib/generators/maintenance_tasks/task_generator.rb
|
@@ -144,7 +147,7 @@ homepage: https://github.com/Shopify/maintenance_tasks
|
|
144
147
|
licenses:
|
145
148
|
- MIT
|
146
149
|
metadata:
|
147
|
-
source_code_uri: https://github.com/Shopify/maintenance_tasks/tree/v1.
|
150
|
+
source_code_uri: https://github.com/Shopify/maintenance_tasks/tree/v1.7.0
|
148
151
|
allowed_push_host: https://rubygems.org
|
149
152
|
post_install_message:
|
150
153
|
rdoc_options: []
|