maintenance_tasks 2.10.1 → 2.11.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 +43 -29
- data/app/helpers/maintenance_tasks/application_helper.rb +1 -1
- data/app/jobs/concerns/maintenance_tasks/task_job_concern.rb +12 -3
- data/app/models/maintenance_tasks/run.rb +1 -5
- data/app/models/maintenance_tasks/task.rb +15 -0
- data/app/views/maintenance_tasks/runs/_run.html.erb +1 -1
- data/app/views/maintenance_tasks/tasks/_task.html.erb +1 -1
- data/lib/maintenance_tasks/engine.rb +6 -0
- data/lib/maintenance_tasks.rb +26 -12
- metadata +12 -14
- data/lib/patches/active_record_batch_enumerator.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4ac2fd148131a277d37ddc609173b8549d01d3e6a9f78786cf729bd5da4f65b0
|
4
|
+
data.tar.gz: a2db7dfe8a9b0a958d943f88305fbe6d8988fd171901c49cd688070d8125124e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8e4c707d55ca479cca9f1592cc65359cc460d70cfd1e4ea4b2caf7c0a92617b4f243feb83c9f3657cb81a76691ed660c91bdafba73634b819a0fa44a719a2c8
|
7
|
+
data.tar.gz: 0efab90ffbdea1131f72de57443c8ed01fc30550d88c3ebbfe77b8e48a37c27dec8ec2ed7591ebdf9ea463e82ff4df7fcb649b111076a7302e10fce5720eb437
|
data/README.md
CHANGED
@@ -74,9 +74,9 @@ 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
|
-
|
78
|
-
|
79
|
-
|
77
|
+
This gem uses the [Rails Error Reporter](https://guides.rubyonrails.org/error_reporting.html) to report errors. If you are using a bug
|
78
|
+
tracking service you may want to subscribe to the reporter. See [Reporting Errors](#reporting-errors)
|
79
|
+
for more information.
|
80
80
|
|
81
81
|
### Active Job Dependency
|
82
82
|
|
@@ -988,44 +988,58 @@ If you are stuck in `pausing` and wish to preserve your tasks's position
|
|
988
988
|
There are a few configurable options for the gem. Custom configurations should
|
989
989
|
be placed in a `maintenance_tasks.rb` initializer.
|
990
990
|
|
991
|
-
####
|
991
|
+
#### Reporting errors
|
992
992
|
|
993
993
|
Exceptions raised while a Task is performing are rescued and information about
|
994
994
|
the error is persisted and visible in the UI.
|
995
995
|
|
996
|
-
|
997
|
-
|
996
|
+
Errors are also sent to the `Rails.error.reporter`, which can be configured by your
|
997
|
+
application. See the [Error Reporting in Rails Applications](https://guides.rubyonrails.org/error_reporting.html) guide for more details.
|
998
998
|
|
999
|
-
|
1000
|
-
# config/initializers/maintenance_tasks.rb
|
1001
|
-
|
1002
|
-
MaintenanceTasks.error_handler = ->(error, task_context, _errored_element) do
|
1003
|
-
Bugsnag.notify(error) do |notification|
|
1004
|
-
notification.add_metadata(:task, task_context)
|
1005
|
-
end
|
1006
|
-
end
|
1007
|
-
```
|
1008
|
-
|
1009
|
-
The error handler should be a lambda that accepts three arguments:
|
999
|
+
Reports to the error reporter will contain the following data:
|
1010
1000
|
|
1011
1001
|
* `error`: The exception that was raised.
|
1012
|
-
* `
|
1002
|
+
* `context`: A hash with additional information about the Task and the
|
1013
1003
|
error:
|
1014
1004
|
* `task_name`: The name of the Task that errored
|
1015
1005
|
* `started_at`: The time the Task started
|
1016
1006
|
* `ended_at`: The time the Task errored
|
1007
|
+
* `run_id`: The id of the errored Task run
|
1008
|
+
* `tick_count`: The tick count at the time of the error
|
1009
|
+
* `errored_element`: The element, if any, that was being processed when the Task
|
1010
|
+
raised an exception. If you would like to pass this object to your exception
|
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`
|
1015
|
+
|
1016
|
+
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
|
+
your Task failed).
|
1019
|
+
|
1020
|
+
#### Reporting errors during iteration
|
1021
|
+
|
1022
|
+
By default, errors raised during task iteration will be raised to the application
|
1023
|
+
and iteration will stop. However, you may want to handle some errors and continue
|
1024
|
+
iteration. `MaintenanceTasks::Task.report_on` can be used to rescue certain
|
1025
|
+
exceptions and report them to the Rails error reporter.
|
1026
|
+
|
1027
|
+
```ruby
|
1028
|
+
class MyTask < MaintenanceTasks::Task
|
1029
|
+
report_on(MyException)
|
1030
|
+
end
|
1031
|
+
```
|
1032
|
+
|
1033
|
+
`MaintenanceTasks::Task` also includes `ActiveSupport::Rescuable` which you can use
|
1034
|
+
to implement custom error handling.
|
1017
1035
|
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
tracker. For example, Bugsnag only sends the id and class name of Active
|
1026
|
-
Record objects in order to protect sensitive data. CSV rows, on the other
|
1027
|
-
hand, are converted to strings and passed raw to Bugsnag, so make sure to
|
1028
|
-
filter any personal data from these objects before adding them to a report.
|
1036
|
+
```ruby
|
1037
|
+
class MyTask < MaintenanceTasks::Task
|
1038
|
+
rescue_from(MyException) do |exception|
|
1039
|
+
handle(exception)
|
1040
|
+
end
|
1041
|
+
end
|
1042
|
+
```
|
1029
1043
|
|
1030
1044
|
#### Customizing the maintenance tasks module
|
1031
1045
|
|
@@ -14,7 +14,7 @@ module MaintenanceTasks
|
|
14
14
|
# @param datetime [ActiveSupport::TimeWithZone] the time to be presented.
|
15
15
|
# @return [String] the HTML to render with the relative datetime in words.
|
16
16
|
def time_ago(datetime)
|
17
|
-
time_tag(datetime, title: datetime.utc
|
17
|
+
time_tag(datetime, title: datetime.utc, class: "is-clickable") do
|
18
18
|
time_ago_in_words(datetime) + " ago"
|
19
19
|
end
|
20
20
|
end
|
@@ -112,7 +112,7 @@ module MaintenanceTasks
|
|
112
112
|
end
|
113
113
|
rescue => error
|
114
114
|
@errored_element = input
|
115
|
-
raise error
|
115
|
+
raise error unless @task.rescue_with_handler(error)
|
116
116
|
end
|
117
117
|
|
118
118
|
def before_perform
|
@@ -181,11 +181,20 @@ module MaintenanceTasks
|
|
181
181
|
task_name: @run.task_name,
|
182
182
|
started_at: @run.started_at,
|
183
183
|
ended_at: @run.ended_at,
|
184
|
+
run_id: @run.id,
|
185
|
+
tick_count: @run.tick_count,
|
184
186
|
}
|
185
187
|
end
|
186
|
-
errored_element = @errored_element if defined?(@errored_element)
|
188
|
+
task_context[:errored_element] = @errored_element if defined?(@errored_element)
|
187
189
|
ensure
|
188
|
-
MaintenanceTasks.error_handler
|
190
|
+
if MaintenanceTasks.instance_variable_get(:@error_handler)
|
191
|
+
errored_element = task_context.delete(:errored_element)
|
192
|
+
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
|
+
else
|
196
|
+
Rails.error.report(error, handled: true, context: task_context)
|
197
|
+
end
|
189
198
|
end
|
190
199
|
end
|
191
200
|
end
|
@@ -33,11 +33,7 @@ module MaintenanceTasks
|
|
33
33
|
]
|
34
34
|
COMPLETED_STATUSES = [:succeeded, :errored, :cancelled]
|
35
35
|
|
36
|
-
|
37
|
-
enum :status, STATUSES.to_h { |status| [status, status.to_s] }
|
38
|
-
else
|
39
|
-
enum status: STATUSES.to_h { |status| [status, status.to_s] }
|
40
|
-
end
|
36
|
+
enum :status, STATUSES.to_h { |status| [status, status.to_s] }
|
41
37
|
|
42
38
|
after_save :instrument_status_change
|
43
39
|
|
@@ -8,6 +8,7 @@ module MaintenanceTasks
|
|
8
8
|
include ActiveModel::Attributes
|
9
9
|
include ActiveModel::AttributeAssignment
|
10
10
|
include ActiveModel::Validations
|
11
|
+
include ActiveSupport::Rescuable
|
11
12
|
|
12
13
|
class NotFoundError < NameError; end
|
13
14
|
|
@@ -200,6 +201,20 @@ module MaintenanceTasks
|
|
200
201
|
set_callback(:error, :after, *filter_list, &block)
|
201
202
|
end
|
202
203
|
|
204
|
+
# Rescue listed exceptions during an iteration and report them to the error reporter, then
|
205
|
+
# continue iteration.
|
206
|
+
#
|
207
|
+
# @param exceptions list of exceptions to rescue and report
|
208
|
+
def report_on(*exceptions)
|
209
|
+
rescue_from(*exceptions) do |exception|
|
210
|
+
if Rails.gem_version >= Gem::Version.new("7.1")
|
211
|
+
Rails.error.report(exception, source: "maintenance_tasks")
|
212
|
+
else
|
213
|
+
Rails.error.report(exception, handled: true)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
203
218
|
private
|
204
219
|
|
205
220
|
def load_constants
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<div class="box">
|
2
2
|
<h5 class="title is-5">
|
3
|
-
<%= time_tag run.created_at, title: run.created_at.utc
|
3
|
+
<%= time_tag run.created_at, title: run.created_at.utc %>
|
4
4
|
<%= status_tag run.status %>
|
5
5
|
<span class="is-pulled-right" title="Run ID">#<%= run.id %></span>
|
6
6
|
</h5>
|
@@ -21,6 +21,12 @@ module MaintenanceTasks
|
|
21
21
|
MaintenanceTasks.backtrace_cleaner = Rails.backtrace_cleaner
|
22
22
|
end
|
23
23
|
|
24
|
+
if Rails.gem_version >= Gem::Version.new("7.1")
|
25
|
+
initializer "maintenance_tasks.deprecator" do
|
26
|
+
Rails.application.deprecators[:maintenance_tasks] = MaintenanceTasks.deprecator
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
24
30
|
config.to_prepare do
|
25
31
|
_ = TaskJobConcern # load this for JobIteration compatibility check
|
26
32
|
end
|
data/lib/maintenance_tasks.rb
CHANGED
@@ -8,8 +8,6 @@ require "active_record"
|
|
8
8
|
require "job-iteration"
|
9
9
|
require "maintenance_tasks/engine"
|
10
10
|
|
11
|
-
require "patches/active_record_batch_enumerator"
|
12
|
-
|
13
11
|
# The engine's namespace module. It provides isolation between the host
|
14
12
|
# application's code and the engine-specific code. Top-level engine constants
|
15
13
|
# and variables are defined under this module.
|
@@ -63,16 +61,6 @@ module MaintenanceTasks
|
|
63
61
|
# use when cleaning a Run's backtrace.
|
64
62
|
mattr_accessor :backtrace_cleaner
|
65
63
|
|
66
|
-
# @!attribute error_handler
|
67
|
-
# @scope class
|
68
|
-
#
|
69
|
-
# The callback to perform when an error occurs in the Task. See the
|
70
|
-
# {file:README#label-Customizing+the+error+handler} for details.
|
71
|
-
#
|
72
|
-
# @return [Proc] the callback to perform when an error occurs in the Task.
|
73
|
-
mattr_accessor :error_handler, default:
|
74
|
-
->(_error, _task_context, _errored_element) {}
|
75
|
-
|
76
64
|
# @!attribute parent_controller
|
77
65
|
# @scope class
|
78
66
|
#
|
@@ -96,4 +84,30 @@ module MaintenanceTasks
|
|
96
84
|
#
|
97
85
|
# @return [ActiveSupport::Duration] the threshold in seconds after which a task is considered stuck.
|
98
86
|
mattr_accessor :stuck_task_duration, default: 5.minutes
|
87
|
+
|
88
|
+
class << self
|
89
|
+
DEPRECATION_MESSAGE = "MaintenanceTasks.error_handler is deprecated and will be removed in the 3.0 release. " \
|
90
|
+
"Instead, reports will be sent to the Rails error reporter. Do not set a handler and subscribe" \
|
91
|
+
"to the error reporter instead."
|
92
|
+
private_constant :DEPRECATION_MESSAGE
|
93
|
+
|
94
|
+
# @deprecated
|
95
|
+
def error_handler
|
96
|
+
deprecator.warn(DEPRECATION_MESSAGE)
|
97
|
+
|
98
|
+
@error_handler
|
99
|
+
end
|
100
|
+
|
101
|
+
# @deprecated
|
102
|
+
def error_handler=(proc)
|
103
|
+
deprecator.warn(DEPRECATION_MESSAGE)
|
104
|
+
|
105
|
+
@error_handler = proc
|
106
|
+
end
|
107
|
+
|
108
|
+
# @api-private
|
109
|
+
def deprecator
|
110
|
+
@deprecator ||= ActiveSupport::Deprecation.new("3.0", "MaintenanceTasks")
|
111
|
+
end
|
112
|
+
end
|
99
113
|
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: maintenance_tasks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.11.0
|
5
5
|
platform: ruby
|
6
|
-
original_platform: ''
|
7
6
|
authors:
|
8
7
|
- Shopify Engineering
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-01-28 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: actionpack
|
@@ -16,42 +15,42 @@ dependencies:
|
|
16
15
|
requirements:
|
17
16
|
- - ">="
|
18
17
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
18
|
+
version: '7.0'
|
20
19
|
type: :runtime
|
21
20
|
prerelease: false
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
23
22
|
requirements:
|
24
23
|
- - ">="
|
25
24
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
25
|
+
version: '7.0'
|
27
26
|
- !ruby/object:Gem::Dependency
|
28
27
|
name: activejob
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
30
29
|
requirements:
|
31
30
|
- - ">="
|
32
31
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
32
|
+
version: '7.0'
|
34
33
|
type: :runtime
|
35
34
|
prerelease: false
|
36
35
|
version_requirements: !ruby/object:Gem::Requirement
|
37
36
|
requirements:
|
38
37
|
- - ">="
|
39
38
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
39
|
+
version: '7.0'
|
41
40
|
- !ruby/object:Gem::Dependency
|
42
41
|
name: activerecord
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
44
43
|
requirements:
|
45
44
|
- - ">="
|
46
45
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
46
|
+
version: '7.0'
|
48
47
|
type: :runtime
|
49
48
|
prerelease: false
|
50
49
|
version_requirements: !ruby/object:Gem::Requirement
|
51
50
|
requirements:
|
52
51
|
- - ">="
|
53
52
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
53
|
+
version: '7.0'
|
55
54
|
- !ruby/object:Gem::Dependency
|
56
55
|
name: csv
|
57
56
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,14 +85,14 @@ dependencies:
|
|
86
85
|
requirements:
|
87
86
|
- - ">="
|
88
87
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
88
|
+
version: '7.0'
|
90
89
|
type: :runtime
|
91
90
|
prerelease: false
|
92
91
|
version_requirements: !ruby/object:Gem::Requirement
|
93
92
|
requirements:
|
94
93
|
- - ">="
|
95
94
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
95
|
+
version: '7.0'
|
97
96
|
- !ruby/object:Gem::Dependency
|
98
97
|
name: zeitwerk
|
99
98
|
requirement: !ruby/object:Gem::Requirement
|
@@ -178,13 +177,12 @@ files:
|
|
178
177
|
- lib/maintenance_tasks.rb
|
179
178
|
- lib/maintenance_tasks/cli.rb
|
180
179
|
- lib/maintenance_tasks/engine.rb
|
181
|
-
- lib/patches/active_record_batch_enumerator.rb
|
182
180
|
- lib/tasks/maintenance_tasks_tasks.rake
|
183
181
|
homepage: https://github.com/Shopify/maintenance_tasks
|
184
182
|
licenses:
|
185
183
|
- MIT
|
186
184
|
metadata:
|
187
|
-
source_code_uri: https://github.com/Shopify/maintenance_tasks/tree/v2.
|
185
|
+
source_code_uri: https://github.com/Shopify/maintenance_tasks/tree/v2.11.0
|
188
186
|
allowed_push_host: https://rubygems.org
|
189
187
|
rdoc_options: []
|
190
188
|
require_paths:
|
@@ -200,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
200
198
|
- !ruby/object:Gem::Version
|
201
199
|
version: '0'
|
202
200
|
requirements: []
|
203
|
-
rubygems_version: 3.6.
|
201
|
+
rubygems_version: 3.6.3
|
204
202
|
specification_version: 4
|
205
203
|
summary: A Rails engine for queuing and managing maintenance tasks
|
206
204
|
test_files: []
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
if Rails.gem_version < Gem::Version.new("7.0")
|
4
|
-
# Add attribute readers.
|
5
|
-
module ActiveRecordBatchEnumerator
|
6
|
-
# The primary key value from which the BatchEnumerator starts,
|
7
|
-
# inclusive of the value.
|
8
|
-
attr_reader :start
|
9
|
-
|
10
|
-
# The primary key value at which the BatchEnumerator ends,
|
11
|
-
# inclusive of the value.
|
12
|
-
attr_reader :finish
|
13
|
-
|
14
|
-
# The relation from which the BatchEnumerator yields batches.
|
15
|
-
attr_reader :relation
|
16
|
-
|
17
|
-
# The size of the batches yielded by the BatchEnumerator.
|
18
|
-
def batch_size
|
19
|
-
@of
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
ActiveRecord::Batches::BatchEnumerator.include(ActiveRecordBatchEnumerator)
|
24
|
-
end
|