maintenance_tasks 2.11.0 → 2.13.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 +4 -4
- data/README.md +145 -44
- data/app/controllers/maintenance_tasks/application_controller.rb +15 -5
- data/app/helpers/maintenance_tasks/tasks_helper.rb +28 -11
- data/app/jobs/concerns/maintenance_tasks/task_job_concern.rb +24 -4
- data/app/models/maintenance_tasks/run.rb +102 -66
- data/app/models/maintenance_tasks/task.rb +33 -6
- data/app/models/maintenance_tasks/task_data_index.rb +2 -1
- data/app/views/layouts/maintenance_tasks/_navbar.html.erb +1 -1
- data/app/views/layouts/maintenance_tasks/application.html.erb +35 -4
- data/app/views/maintenance_tasks/runs/_arguments.html.erb +1 -1
- data/app/views/maintenance_tasks/runs/_run.html.erb +14 -8
- data/app/views/maintenance_tasks/runs/_serializable.html.erb +15 -18
- data/app/views/maintenance_tasks/tasks/_task.html.erb +4 -4
- data/app/views/maintenance_tasks/tasks/index.html.erb +6 -4
- data/app/views/maintenance_tasks/tasks/show.html.erb +16 -12
- data/db/migrate/20201211151756_create_maintenance_tasks_runs.rb +10 -2
- data/db/migrate/20210219212931_change_cursor_to_string.rb +1 -1
- data/db/migrate/20210225152418_remove_index_on_task_name.rb +1 -1
- data/db/migrate/20210517131953_add_arguments_to_maintenance_tasks_runs.rb +1 -1
- data/db/migrate/20211210152329_add_lock_version_to_maintenance_tasks_runs.rb +1 -1
- data/db/migrate/20220706101937_change_runs_tick_columns_to_bigints.rb +1 -1
- data/db/migrate/20220713131925_add_index_on_task_name_and_status_to_runs.rb +1 -1
- data/db/migrate/20230622035229_add_metadata_to_runs.rb +1 -1
- data/lib/maintenance_tasks/engine.rb +2 -4
- data/lib/maintenance_tasks.rb +25 -1
- metadata +13 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8402f1f4b8919e892a6334373ad397d49b5c6c78893f2f107b990b90653435d1
|
|
4
|
+
data.tar.gz: 1459d5b92233a1196aeb83c80bec9da525f04e975a50f6a415cdcd8dc647bd59
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3dff16b85a650f4d73cf79df20267d1278b1181f2ba6717742581909ebfd39145dfdd9b9cf1453edaa785474fb6f7dda87af2bad534e6398bf010945b02f2da3
|
|
7
|
+
data.tar.gz: c7b75c1edc684fad66c5080ee3642fe469038e1f4ab2329ead0fd3c65e5f0ca2a940250dc988658dce672e2de0d056741b9a317310afa23165ba27794722ce1d
|
data/README.md
CHANGED
|
@@ -74,9 +74,11 @@ The generator creates and runs a migration to add the necessary table to your
|
|
|
74
74
|
database. It also mounts Maintenance Tasks in your `config/routes.rb`. By
|
|
75
75
|
default the web UI can be accessed in the new `/maintenance_tasks` path.
|
|
76
76
|
|
|
77
|
-
This gem uses the [Rails Error Reporter]
|
|
78
|
-
tracking service you may want to subscribe to the
|
|
79
|
-
for more information.
|
|
77
|
+
This gem uses the [Rails Error Reporter][rails-error-reporting] to report errors.
|
|
78
|
+
If you are using a bug tracking service you may want to subscribe to the
|
|
79
|
+
reporter. See [Reporting Errors](#reporting-errors) for more information.
|
|
80
|
+
|
|
81
|
+
[rails-error-reporting]: https://guides.rubyonrails.org/error_reporting.html
|
|
80
82
|
|
|
81
83
|
### Active Job Dependency
|
|
82
84
|
|
|
@@ -114,12 +116,12 @@ The typical Maintenance Tasks workflow is as follows:
|
|
|
114
116
|
1. [Generate a class describing the Task](#creating-a-task) and the work to be
|
|
115
117
|
done.
|
|
116
118
|
2. Run the Task
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
- either by [using the included web UI](#running-a-task-from-the-web-ui),
|
|
120
|
+
- or by [using the command line](#running-a-task-from-the-command-line),
|
|
121
|
+
- or by [using Ruby](#running-a-task-from-ruby).
|
|
120
122
|
3. [Monitor the Task](#monitoring-your-tasks-status)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
+
- either by using the included web UI,
|
|
124
|
+
- or by manually checking your task’s run’s status in your database.
|
|
123
125
|
4. Optionally, delete the Task code if you no longer need it.
|
|
124
126
|
|
|
125
127
|
### Creating a Task
|
|
@@ -168,7 +170,8 @@ end
|
|
|
168
170
|
When processing records from an Active Record Relation, records are fetched in
|
|
169
171
|
batches internally, and then each record is passed to the `#process` method.
|
|
170
172
|
Maintenance Tasks will query the database to fetch records in batches of 100 by
|
|
171
|
-
default, but the batch size can be modified using the `collection_batch_size`
|
|
173
|
+
default, but the batch size can be modified using the `collection_batch_size`
|
|
174
|
+
macro:
|
|
172
175
|
|
|
173
176
|
```ruby
|
|
174
177
|
# app/tasks/maintenance/update_posts_task.rb
|
|
@@ -502,13 +505,44 @@ set of values will be used to populate a dropdown in the user interface. The
|
|
|
502
505
|
following types are supported:
|
|
503
506
|
|
|
504
507
|
* Arrays
|
|
505
|
-
* Procs and lambdas that optionally accept the Task instance, and return an
|
|
506
|
-
|
|
508
|
+
* Procs and lambdas that optionally accept the Task instance, and return an
|
|
509
|
+
Array.
|
|
510
|
+
* Callable objects that receive one argument, the Task instance, and return an
|
|
511
|
+
Array.
|
|
507
512
|
* Methods that return an Array, called on the Task instance.
|
|
508
513
|
|
|
509
514
|
For enumerables that don't match the supported types, a text field will be
|
|
510
515
|
rendered instead.
|
|
511
516
|
|
|
517
|
+
### Masking Task Parameters
|
|
518
|
+
|
|
519
|
+
Task attributes can be masked in the UI by adding `mask_attribute` class method
|
|
520
|
+
in the task class. This will replace the value in the arguments list with
|
|
521
|
+
`[FILTERED]` in the UI.
|
|
522
|
+
|
|
523
|
+
```ruby
|
|
524
|
+
# app/tasks/maintenance/sensitive_params_task.rb
|
|
525
|
+
|
|
526
|
+
module Maintenance
|
|
527
|
+
class SensitiveParamsTask < MaintenanceTasks::Task
|
|
528
|
+
attribute :sensitive_content, :string
|
|
529
|
+
|
|
530
|
+
mask_attribute :sensitive_content
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
If you have any filtered parameters in the global [Rails parameter
|
|
536
|
+
filter][rails-parameter-filter], they will be automatically taken into account
|
|
537
|
+
when masking the parameters, which means that you can mask parameters across all
|
|
538
|
+
tasks by adding them to the global rails parameters filter.
|
|
539
|
+
|
|
540
|
+
[rails-parameter-filter]:https://guides.rubyonrails.org/configuring.html#config-filter-parameters
|
|
541
|
+
|
|
542
|
+
```ruby
|
|
543
|
+
Rails.application.config.filter_parameters += %i[token]
|
|
544
|
+
```
|
|
545
|
+
|
|
512
546
|
### Custom cursor columns to improve performance
|
|
513
547
|
|
|
514
548
|
The [job-iteration gem][job-iteration], on which this gem depends, adds an
|
|
@@ -899,10 +933,10 @@ a Task can be in:
|
|
|
899
933
|
|
|
900
934
|
The Maintenance Tasks engine uses Rails sessions for flash messages and storing
|
|
901
935
|
the CSRF token. For the engine to work in an API-only Rails application, you
|
|
902
|
-
need to add a [session middleware][] and the `ActionDispatch::Flash`
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
936
|
+
need to add a [session middleware][] and the `ActionDispatch::Flash` middleware.
|
|
937
|
+
The engine also defines a strict [Content Security Policy][], make sure to
|
|
938
|
+
include `ActionDispatch::ContentSecurityPolicy::Middleware` in your app's
|
|
939
|
+
middleware stack to ensure the CSP is delivered to the user's browser.
|
|
906
940
|
|
|
907
941
|
[session middleware]: https://guides.rubyonrails.org/api_app.html#using-session-middlewares
|
|
908
942
|
[Content Security Policy]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
|
|
@@ -926,8 +960,8 @@ module YourApplication
|
|
|
926
960
|
end
|
|
927
961
|
```
|
|
928
962
|
|
|
929
|
-
You can read more in the [Using Rails for API-only Applications][rails api]
|
|
930
|
-
guide.
|
|
963
|
+
You can read more in the [Using Rails for API-only Applications][rails api]
|
|
964
|
+
Rails guide.
|
|
931
965
|
|
|
932
966
|
[rails api]: https://guides.rubyonrails.org/api_app.html
|
|
933
967
|
|
|
@@ -944,9 +978,9 @@ infrastructure or code changes.
|
|
|
944
978
|
This means a Task can safely be interrupted, re-enqueued and resumed without any
|
|
945
979
|
intervention at the end of an iteration, after the `process` method returns.
|
|
946
980
|
|
|
947
|
-
By default, a running Task will be interrupted after running for more 5
|
|
948
|
-
This is [configured in the `job-iteration` gem][max-job-runtime] and
|
|
949
|
-
tweaked in an initializer if necessary.
|
|
981
|
+
By default, a running Task will be interrupted after running for more than 5
|
|
982
|
+
minutes. This is [configured in the `job-iteration` gem][max-job-runtime] and
|
|
983
|
+
can be tweaked in an initializer if necessary.
|
|
950
984
|
|
|
951
985
|
[max-job-runtime]: https://github.com/Shopify/job-iteration/blob/-/guides/best-practices.md#max-job-runtime
|
|
952
986
|
|
|
@@ -993,45 +1027,76 @@ be placed in a `maintenance_tasks.rb` initializer.
|
|
|
993
1027
|
Exceptions raised while a Task is performing are rescued and information about
|
|
994
1028
|
the error is persisted and visible in the UI.
|
|
995
1029
|
|
|
996
|
-
Errors are also sent to
|
|
997
|
-
application. See the [Error Reporting in Rails
|
|
1030
|
+
Errors are also sent to `Rails.error.report`, which can be configured by
|
|
1031
|
+
your application. See the [Error Reporting in Rails
|
|
1032
|
+
Applications][rails-error-reporting] guide for more details.
|
|
998
1033
|
|
|
999
1034
|
Reports to the error reporter will contain the following data:
|
|
1000
1035
|
|
|
1001
1036
|
* `error`: The exception that was raised.
|
|
1002
|
-
* `context`: A hash with additional information about the Task and the
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
monitoring service, make sure you **sanitize the object** to avoid leaking
|
|
1012
|
-
sensitive data and **convert it to a format** that is compatible with your bug
|
|
1013
|
-
tracker.
|
|
1014
|
-
* `source`: This will be `maintenance_tasks`
|
|
1037
|
+
* `context`: A hash with additional information about the Task and the error:
|
|
1038
|
+
* `task_name`: The name of the Task that errored
|
|
1039
|
+
* `started_at`: The time the Task started
|
|
1040
|
+
* `ended_at`: The time the Task errored
|
|
1041
|
+
* `run_id`: The id of the errored Task run
|
|
1042
|
+
* `tick_count`: The tick count at the time of the error
|
|
1043
|
+
* `errored_element`: The element, if any, that was being processed when the
|
|
1044
|
+
* `source`: This will be `maintenance-tasks`
|
|
1045
|
+
* `handled`: the value of `MaintenanceTasks.report_errors_as_handled` (default `true`, see below)
|
|
1015
1046
|
|
|
1016
1047
|
Note that `context` may be empty if the Task produced an error before any
|
|
1017
|
-
context could be gathered (for example, if deserializing the job to process
|
|
1018
|
-
|
|
1048
|
+
context could be gathered (for example, if deserializing the job to process your
|
|
1049
|
+
Task failed).
|
|
1050
|
+
|
|
1051
|
+
Here's an example custom subscriber to the Rails error reporter for integrating
|
|
1052
|
+
with an exception monitoring service (Bugsnag):
|
|
1053
|
+
|
|
1054
|
+
```ruby
|
|
1055
|
+
# config/initializers/maintenance_tasks.rb
|
|
1056
|
+
MaintenanceTasks.report_errors_as_handled = false
|
|
1057
|
+
|
|
1058
|
+
class MaintenanceTasksErrorSubscriber
|
|
1059
|
+
def report(error, handled:, severity:, context:, source: nil)
|
|
1060
|
+
return unless source == "maintenance-tasks"
|
|
1061
|
+
|
|
1062
|
+
unless handled
|
|
1063
|
+
Bugsnag.notify(error) do |notification|
|
|
1064
|
+
notification.add_metadata(:task, context)
|
|
1065
|
+
end
|
|
1066
|
+
else
|
|
1067
|
+
Rails.logger.info(error)
|
|
1068
|
+
end
|
|
1069
|
+
end
|
|
1070
|
+
end
|
|
1071
|
+
|
|
1072
|
+
Rails.error.subscribe(MaintenanceTasksErrorSubscriber.new)
|
|
1073
|
+
```
|
|
1074
|
+
|
|
1075
|
+
`MaintenanceTasks.report_errors_as_handled` determines the value for `handled` in this example.
|
|
1076
|
+
By default (for backwards compatibility) this is `true`.
|
|
1077
|
+
Setting this to `false` provides more accurate error reporting as it allows to distinguish between
|
|
1078
|
+
expected (e.g., via `report_on`) and unexpected errors in error subscribers.
|
|
1079
|
+
`false` will be the default in v3.0.
|
|
1019
1080
|
|
|
1020
1081
|
#### Reporting errors during iteration
|
|
1021
1082
|
|
|
1022
|
-
By default, errors raised during task iteration will be raised to the
|
|
1023
|
-
and iteration will stop. However, you may want to handle some errors
|
|
1024
|
-
iteration. `MaintenanceTasks::Task.report_on` can be used to rescue
|
|
1025
|
-
exceptions and report them to the Rails error reporter.
|
|
1083
|
+
By default, errors raised during task iteration will be raised to the
|
|
1084
|
+
application and iteration will stop. However, you may want to handle some errors
|
|
1085
|
+
and continue iteration. `MaintenanceTasks::Task.report_on` can be used to rescue
|
|
1086
|
+
certain exceptions and report them to the Rails error reporter. Any keyword
|
|
1087
|
+
arguments are passed to
|
|
1088
|
+
[ActiveSupport::ErrorReporter#report][as-error-reporter-report]:
|
|
1089
|
+
|
|
1090
|
+
[as-error-reporter-report]: https://api.rubyonrails.org/classes/ActiveSupport/ErrorReporter.html#method-i-report
|
|
1026
1091
|
|
|
1027
1092
|
```ruby
|
|
1028
1093
|
class MyTask < MaintenanceTasks::Task
|
|
1029
|
-
report_on(MyException)
|
|
1094
|
+
report_on(MyException, OtherException, severity: :info, context: {task_name: "my_task"})
|
|
1030
1095
|
end
|
|
1031
1096
|
```
|
|
1032
1097
|
|
|
1033
|
-
`MaintenanceTasks::Task` also includes `ActiveSupport::Rescuable` which you can
|
|
1034
|
-
to implement custom error handling.
|
|
1098
|
+
`MaintenanceTasks::Task` also includes `ActiveSupport::Rescuable` which you can
|
|
1099
|
+
use to implement custom error handling.
|
|
1035
1100
|
|
|
1036
1101
|
```ruby
|
|
1037
1102
|
class MyTask < MaintenanceTasks::Task
|
|
@@ -1202,6 +1267,42 @@ The value for `MaintenanceTasks.stuck_task_duration` must be an
|
|
|
1202
1267
|
`ActiveSupport::Duration`. If no value is specified, it will default to 5
|
|
1203
1268
|
minutes.
|
|
1204
1269
|
|
|
1270
|
+
#### Configure status reload frequency
|
|
1271
|
+
|
|
1272
|
+
`MaintenanceTasks.status_reload_frequency` can be configured to specify how often
|
|
1273
|
+
the run status should be reloaded during iteration. By default, the status is
|
|
1274
|
+
reloaded every second, but this can be increased to improve performance. Note that increasing the reload interval impacts how quickly
|
|
1275
|
+
your task will stop if it is paused or interrupted.
|
|
1276
|
+
|
|
1277
|
+
```ruby
|
|
1278
|
+
# config/initializers/maintenance_tasks.rb
|
|
1279
|
+
MaintenanceTasks.status_reload_frequency = 10.seconds # Reload status every 10 seconds
|
|
1280
|
+
```
|
|
1281
|
+
|
|
1282
|
+
Individual tasks can also override this setting using the `reload_status_every` method:
|
|
1283
|
+
|
|
1284
|
+
```ruby
|
|
1285
|
+
# app/tasks/maintenance/update_posts_task.rb
|
|
1286
|
+
|
|
1287
|
+
module Maintenance
|
|
1288
|
+
class UpdatePostsTask < MaintenanceTasks::Task
|
|
1289
|
+
# Reload status every 5 seconds instead of the global default
|
|
1290
|
+
reload_status_every(5.seconds)
|
|
1291
|
+
|
|
1292
|
+
def collection
|
|
1293
|
+
Post.all
|
|
1294
|
+
end
|
|
1295
|
+
|
|
1296
|
+
def process(post)
|
|
1297
|
+
post.update!(content: "New content!")
|
|
1298
|
+
end
|
|
1299
|
+
end
|
|
1300
|
+
end
|
|
1301
|
+
```
|
|
1302
|
+
|
|
1303
|
+
This optimization can significantly reduce database queries, especially for short iterations.
|
|
1304
|
+
This is especially useful if the task doesn't need to check for cancellation/pausing very often.
|
|
1305
|
+
|
|
1205
1306
|
#### Metadata
|
|
1206
1307
|
|
|
1207
1308
|
`MaintenanceTasks.metadata` can be configured to specify a proc from which to
|
|
@@ -8,16 +8,26 @@ module MaintenanceTasks
|
|
|
8
8
|
BULMA_CDN = "https://cdn.jsdelivr.net"
|
|
9
9
|
|
|
10
10
|
content_security_policy do |policy|
|
|
11
|
-
policy.
|
|
11
|
+
policy.style_src_elem(
|
|
12
12
|
BULMA_CDN,
|
|
13
|
-
#
|
|
14
|
-
"'sha256-
|
|
13
|
+
# <style> tag in app/views/layouts/maintenance_tasks/application.html.erb
|
|
14
|
+
"'sha256-WHHDQLdkleXnAN5zs0GDXC5ls41CHUaVsJtVpaNx+EM='",
|
|
15
15
|
)
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
capybara_lockstep_scripts = [
|
|
17
|
+
"'sha256-1AoN3ZtJC5OvqkMgrYvhZjp4kI8QjJjO7TAyKYiDw+U='",
|
|
18
|
+
"'sha256-QVSzZi6ZsX/cu4h+hIs1iVivG1BxUmJggiEsGDIXBG0='", # with debug on
|
|
19
|
+
] if defined?(Capybara::Lockstep)
|
|
20
|
+
policy.script_src_elem(
|
|
21
|
+
# <script> tag in app/views/layouts/maintenance_tasks/application.html.erb
|
|
18
22
|
"'sha256-NiHKryHWudRC2IteTqmY9v1VkaDUA/5jhgXkMTkgo2w='",
|
|
23
|
+
# <script> tag for capybara-lockstep
|
|
24
|
+
*capybara_lockstep_scripts,
|
|
19
25
|
)
|
|
26
|
+
|
|
27
|
+
policy.require_trusted_types_for # disable because we use new DOMParser().parseFromString
|
|
20
28
|
policy.frame_ancestors(:self)
|
|
29
|
+
policy.connect_src(:self)
|
|
30
|
+
policy.form_action(:self)
|
|
21
31
|
end
|
|
22
32
|
|
|
23
33
|
protect_from_forgery with: :exception
|
|
@@ -47,7 +47,7 @@ module MaintenanceTasks
|
|
|
47
47
|
progress_bar = tag.progress(
|
|
48
48
|
value: progress.value,
|
|
49
49
|
max: progress.max,
|
|
50
|
-
class: ["progress"] + STATUS_COLOURS.fetch(run.status),
|
|
50
|
+
class: ["progress", "mt-4"] + STATUS_COLOURS.fetch(run.status),
|
|
51
51
|
)
|
|
52
52
|
progress_text = tag.p(tag.i(progress.text))
|
|
53
53
|
tag.div(progress_bar + progress_text, class: "block")
|
|
@@ -60,7 +60,10 @@ module MaintenanceTasks
|
|
|
60
60
|
# @return [String] the span element containing the status, with the
|
|
61
61
|
# appropriate tag class attached.
|
|
62
62
|
def status_tag(status)
|
|
63
|
-
tag.span(
|
|
63
|
+
tag.span(
|
|
64
|
+
status.capitalize,
|
|
65
|
+
class: ["tag", "has-text-weight-medium", "pr-2", "mr-4"] + STATUS_COLOURS.fetch(status),
|
|
66
|
+
)
|
|
64
67
|
end
|
|
65
68
|
|
|
66
69
|
# Reports the approximate elapsed time a Run has been processed so far based
|
|
@@ -101,7 +104,7 @@ module MaintenanceTasks
|
|
|
101
104
|
)
|
|
102
105
|
end
|
|
103
106
|
|
|
104
|
-
# Resolves values covered by the inclusion validator for a
|
|
107
|
+
# Resolves values covered by the inclusion validator for a Task attribute.
|
|
105
108
|
# Supported option types:
|
|
106
109
|
# - Arrays
|
|
107
110
|
# - Procs and lambdas that optionally accept the Task instance, and return an Array.
|
|
@@ -112,7 +115,7 @@ module MaintenanceTasks
|
|
|
112
115
|
#
|
|
113
116
|
# Returned values are used to populate a dropdown list of options.
|
|
114
117
|
#
|
|
115
|
-
# @param
|
|
118
|
+
# @param task [Task] The Task for which the value needs to be resolved.
|
|
116
119
|
# @param parameter_name [String] The parameter name.
|
|
117
120
|
#
|
|
118
121
|
# @return [Array] value of the resolved inclusion option.
|
|
@@ -149,24 +152,27 @@ module MaintenanceTasks
|
|
|
149
152
|
# If the parameter has a `validates_inclusion_of` validator, return a dropdown list of options instead.
|
|
150
153
|
def parameter_field(form_builder, parameter_name)
|
|
151
154
|
inclusion_values = resolve_inclusion_value(form_builder.object, parameter_name)
|
|
152
|
-
|
|
155
|
+
if inclusion_values
|
|
156
|
+
return tag.div(form_builder.select(parameter_name, inclusion_values, prompt: "Select a value"), class: "select")
|
|
157
|
+
end
|
|
153
158
|
|
|
154
159
|
case form_builder.object.class.attribute_types[parameter_name]
|
|
155
160
|
when ActiveModel::Type::Integer
|
|
156
|
-
form_builder.number_field(parameter_name)
|
|
161
|
+
form_builder.number_field(parameter_name, class: "input")
|
|
157
162
|
when ActiveModel::Type::Decimal, ActiveModel::Type::Float
|
|
158
|
-
form_builder.number_field(parameter_name, { step: "any" })
|
|
163
|
+
form_builder.number_field(parameter_name, { step: "any", class: "input" })
|
|
159
164
|
when ActiveModel::Type::DateTime
|
|
160
|
-
form_builder.datetime_field(parameter_name) + datetime_field_help_text
|
|
165
|
+
form_builder.datetime_field(parameter_name, class: "input") + datetime_field_help_text
|
|
161
166
|
when ActiveModel::Type::Date
|
|
162
|
-
form_builder.date_field(parameter_name)
|
|
167
|
+
form_builder.date_field(parameter_name, class: "input")
|
|
163
168
|
when ActiveModel::Type::Time
|
|
164
|
-
form_builder.time_field(parameter_name)
|
|
169
|
+
form_builder.time_field(parameter_name, class: "input")
|
|
165
170
|
when ActiveModel::Type::Boolean
|
|
166
|
-
form_builder.check_box(parameter_name)
|
|
171
|
+
form_builder.check_box(parameter_name, class: "checkbox")
|
|
167
172
|
else
|
|
168
173
|
form_builder.text_area(parameter_name, class: "textarea")
|
|
169
174
|
end
|
|
175
|
+
.then { |input| tag.div(input, class: "control") }
|
|
170
176
|
end
|
|
171
177
|
|
|
172
178
|
# Return helper text for the datetime-local form field.
|
|
@@ -182,5 +188,16 @@ module MaintenanceTasks
|
|
|
182
188
|
class: "content is-small",
|
|
183
189
|
)
|
|
184
190
|
end
|
|
191
|
+
|
|
192
|
+
# Checks if an attribute is required for a given Task.
|
|
193
|
+
#
|
|
194
|
+
# @param task [MaintenanceTasks::TaskDataShow] The TaskDataShow instance.
|
|
195
|
+
# @param parameter_name [Symbol] The name of the attribute to check.
|
|
196
|
+
# @return [Boolean] Whether the attribute is required.
|
|
197
|
+
def attribute_required?(task, parameter_name)
|
|
198
|
+
task.class.validators_on(parameter_name).any? do |validator|
|
|
199
|
+
validator.kind == :presence
|
|
200
|
+
end
|
|
201
|
+
end
|
|
185
202
|
end
|
|
186
203
|
end
|
|
@@ -101,7 +101,8 @@ module MaintenanceTasks
|
|
|
101
101
|
throw(:abort, :skip_complete_callbacks) if @run.stopping?
|
|
102
102
|
task_iteration(input)
|
|
103
103
|
@ticker.tick
|
|
104
|
-
|
|
104
|
+
|
|
105
|
+
reload_run_status
|
|
105
106
|
end
|
|
106
107
|
|
|
107
108
|
def task_iteration(input)
|
|
@@ -127,6 +128,8 @@ module MaintenanceTasks
|
|
|
127
128
|
@ticker = Ticker.new(MaintenanceTasks.ticker_delay) do |ticks, duration|
|
|
128
129
|
@run.persist_progress(ticks, duration)
|
|
129
130
|
end
|
|
131
|
+
|
|
132
|
+
@last_status_reload = nil
|
|
130
133
|
end
|
|
131
134
|
|
|
132
135
|
def on_start
|
|
@@ -190,11 +193,28 @@ module MaintenanceTasks
|
|
|
190
193
|
if MaintenanceTasks.instance_variable_get(:@error_handler)
|
|
191
194
|
errored_element = task_context.delete(:errored_element)
|
|
192
195
|
MaintenanceTasks.error_handler.call(error, task_context.except(:run_id, :tick_count), errored_element)
|
|
193
|
-
elsif Rails.gem_version >= Gem::Version.new("7.1")
|
|
194
|
-
Rails.error.report(error, context: task_context, source: "maintenance-tasks")
|
|
195
196
|
else
|
|
196
|
-
Rails.error.report(
|
|
197
|
+
Rails.error.report(
|
|
198
|
+
error,
|
|
199
|
+
handled: MaintenanceTasks.report_errors_as_handled,
|
|
200
|
+
context: task_context,
|
|
201
|
+
source: "maintenance-tasks",
|
|
202
|
+
)
|
|
197
203
|
end
|
|
198
204
|
end
|
|
205
|
+
|
|
206
|
+
def reload_run_status
|
|
207
|
+
return unless should_reload_status?
|
|
208
|
+
|
|
209
|
+
@run.reload_status
|
|
210
|
+
@last_status_reload = Time.now
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def should_reload_status?
|
|
214
|
+
return true if @last_status_reload.nil?
|
|
215
|
+
|
|
216
|
+
time_since_last_reload = Time.now - @last_status_reload
|
|
217
|
+
time_since_last_reload >= @task.status_reload_frequency
|
|
218
|
+
end
|
|
199
219
|
end
|
|
200
220
|
end
|