maintenance_tasks 1.3.0 → 1.7.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +288 -45
  3. data/app/controllers/maintenance_tasks/tasks_controller.rb +7 -2
  4. data/app/helpers/maintenance_tasks/application_helper.rb +1 -0
  5. data/app/helpers/maintenance_tasks/tasks_helper.rb +19 -14
  6. data/app/jobs/concerns/maintenance_tasks/task_job_concern.rb +44 -23
  7. data/app/models/maintenance_tasks/application_record.rb +1 -0
  8. data/app/models/maintenance_tasks/csv_collection_builder.rb +33 -0
  9. data/app/models/maintenance_tasks/null_collection_builder.rb +31 -0
  10. data/app/models/maintenance_tasks/progress.rb +8 -3
  11. data/app/models/maintenance_tasks/run.rb +224 -18
  12. data/app/models/maintenance_tasks/runner.rb +26 -7
  13. data/app/models/maintenance_tasks/runs_page.rb +1 -0
  14. data/app/models/maintenance_tasks/task.rb +225 -0
  15. data/app/models/maintenance_tasks/task_data.rb +24 -3
  16. data/app/validators/maintenance_tasks/run_status_validator.rb +2 -2
  17. data/app/views/maintenance_tasks/runs/_arguments.html.erb +22 -0
  18. data/app/views/maintenance_tasks/runs/_csv.html.erb +5 -0
  19. data/app/views/maintenance_tasks/runs/_run.html.erb +18 -1
  20. data/app/views/maintenance_tasks/runs/info/_custom.html.erb +0 -0
  21. data/app/views/maintenance_tasks/runs/info/_errored.html.erb +0 -2
  22. data/app/views/maintenance_tasks/runs/info/_paused.html.erb +2 -2
  23. data/app/views/maintenance_tasks/runs/info/_running.html.erb +3 -5
  24. data/app/views/maintenance_tasks/tasks/_custom.html.erb +0 -0
  25. data/app/views/maintenance_tasks/tasks/_task.html.erb +19 -1
  26. data/app/views/maintenance_tasks/tasks/index.html.erb +2 -2
  27. data/app/views/maintenance_tasks/tasks/show.html.erb +37 -2
  28. data/config/routes.rb +1 -0
  29. data/db/migrate/20201211151756_create_maintenance_tasks_runs.rb +1 -0
  30. data/db/migrate/20210225152418_remove_index_on_task_name.rb +1 -0
  31. data/db/migrate/20210517131953_add_arguments_to_maintenance_tasks_runs.rb +7 -0
  32. data/db/migrate/20211210152329_add_lock_version_to_maintenance_tasks_runs.rb +8 -0
  33. data/lib/generators/maintenance_tasks/install_generator.rb +1 -0
  34. data/lib/generators/maintenance_tasks/templates/task.rb.tt +3 -1
  35. data/lib/maintenance_tasks/cli.rb +11 -4
  36. data/lib/maintenance_tasks/engine.rb +15 -1
  37. data/lib/maintenance_tasks.rb +14 -1
  38. data/lib/patches/active_record_batch_enumerator.rb +23 -0
  39. metadata +15 -11
  40. data/app/models/maintenance_tasks/csv_collection.rb +0 -33
  41. data/app/tasks/maintenance_tasks/task.rb +0 -133
  42. data/app/views/maintenance_tasks/runs/_info.html.erb +0 -16
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.3.0
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: 2021-05-13 00:00:00.000000000 Z
11
+ date: 2022-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -97,21 +97,24 @@ files:
97
97
  - app/jobs/concerns/maintenance_tasks/task_job_concern.rb
98
98
  - app/jobs/maintenance_tasks/task_job.rb
99
99
  - app/models/maintenance_tasks/application_record.rb
100
- - app/models/maintenance_tasks/csv_collection.rb
100
+ - app/models/maintenance_tasks/csv_collection_builder.rb
101
+ - app/models/maintenance_tasks/null_collection_builder.rb
101
102
  - app/models/maintenance_tasks/progress.rb
102
103
  - app/models/maintenance_tasks/run.rb
103
104
  - app/models/maintenance_tasks/runner.rb
104
105
  - app/models/maintenance_tasks/runs_page.rb
106
+ - app/models/maintenance_tasks/task.rb
105
107
  - app/models/maintenance_tasks/task_data.rb
106
108
  - app/models/maintenance_tasks/ticker.rb
107
- - app/tasks/maintenance_tasks/task.rb
108
109
  - app/validators/maintenance_tasks/run_status_validator.rb
109
110
  - app/views/layouts/maintenance_tasks/_navbar.html.erb
110
111
  - app/views/layouts/maintenance_tasks/application.html.erb
111
- - app/views/maintenance_tasks/runs/_info.html.erb
112
+ - app/views/maintenance_tasks/runs/_arguments.html.erb
113
+ - app/views/maintenance_tasks/runs/_csv.html.erb
112
114
  - app/views/maintenance_tasks/runs/_run.html.erb
113
115
  - app/views/maintenance_tasks/runs/info/_cancelled.html.erb
114
116
  - app/views/maintenance_tasks/runs/info/_cancelling.html.erb
117
+ - app/views/maintenance_tasks/runs/info/_custom.html.erb
115
118
  - app/views/maintenance_tasks/runs/info/_enqueued.html.erb
116
119
  - app/views/maintenance_tasks/runs/info/_errored.html.erb
117
120
  - app/views/maintenance_tasks/runs/info/_interrupted.html.erb
@@ -119,12 +122,15 @@ files:
119
122
  - app/views/maintenance_tasks/runs/info/_pausing.html.erb
120
123
  - app/views/maintenance_tasks/runs/info/_running.html.erb
121
124
  - app/views/maintenance_tasks/runs/info/_succeeded.html.erb
125
+ - app/views/maintenance_tasks/tasks/_custom.html.erb
122
126
  - app/views/maintenance_tasks/tasks/_task.html.erb
123
127
  - app/views/maintenance_tasks/tasks/index.html.erb
124
128
  - app/views/maintenance_tasks/tasks/show.html.erb
125
129
  - config/routes.rb
126
130
  - db/migrate/20201211151756_create_maintenance_tasks_runs.rb
127
131
  - db/migrate/20210225152418_remove_index_on_task_name.rb
132
+ - db/migrate/20210517131953_add_arguments_to_maintenance_tasks_runs.rb
133
+ - db/migrate/20211210152329_add_lock_version_to_maintenance_tasks_runs.rb
128
134
  - exe/maintenance_tasks
129
135
  - lib/generators/maintenance_tasks/install_generator.rb
130
136
  - lib/generators/maintenance_tasks/task_generator.rb
@@ -135,17 +141,15 @@ files:
135
141
  - lib/maintenance_tasks.rb
136
142
  - lib/maintenance_tasks/cli.rb
137
143
  - lib/maintenance_tasks/engine.rb
144
+ - lib/patches/active_record_batch_enumerator.rb
138
145
  - lib/tasks/maintenance_tasks_tasks.rake
139
146
  homepage: https://github.com/Shopify/maintenance_tasks
140
147
  licenses:
141
148
  - MIT
142
149
  metadata:
143
- source_code_uri: https://github.com/Shopify/maintenance_tasks/tree/v1.3.0
150
+ source_code_uri: https://github.com/Shopify/maintenance_tasks/tree/v1.7.0
144
151
  allowed_push_host: https://rubygems.org
145
- post_install_message: |-
146
- Thank you for installing Maintenance Tasks 1.3.0. To complete, please run:
147
-
148
- rails generate maintenance_tasks:install
152
+ post_install_message:
149
153
  rdoc_options: []
150
154
  require_paths:
151
155
  - lib
@@ -160,7 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
160
164
  - !ruby/object:Gem::Version
161
165
  version: '0'
162
166
  requirements: []
163
- rubygems_version: 3.2.17
167
+ rubygems_version: 3.2.20
164
168
  signing_key:
165
169
  specification_version: 4
166
170
  summary: A Rails engine for queuing and managing maintenance tasks
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "csv"
4
-
5
- module MaintenanceTasks
6
- # Module that is included into Task classes by Task.csv_collection for
7
- # processing CSV files.
8
- #
9
- # @api private
10
- module CsvCollection
11
- # The contents of a CSV file to be processed by a Task.
12
- #
13
- # @return [String] the content of the CSV file to process.
14
- attr_accessor :csv_content
15
-
16
- # Defines the collection to be iterated over, based on the provided CSV.
17
- #
18
- # @return [CSV] the CSV object constructed from the specified CSV content,
19
- # with headers.
20
- def collection
21
- CSV.new(csv_content, headers: true)
22
- end
23
-
24
- # The number of rows to be processed. Excludes the header row from the count
25
- # and assumed a trailing new line in the CSV file. Note that this number is
26
- # an approximation based on the number of new lines.
27
- #
28
- # @return [Integer] the approximate number of rows to process.
29
- def count
30
- csv_content.count("\n") - 1
31
- end
32
- end
33
- end
@@ -1,133 +0,0 @@
1
- # frozen_string_literal: true
2
- module MaintenanceTasks
3
- # Base class that is inherited by the host application's task classes.
4
- class Task
5
- extend ActiveSupport::DescendantsTracker
6
-
7
- class NotFoundError < NameError; end
8
-
9
- # The throttle conditions for a given Task. This is provided as an array of
10
- # hashes, with each hash specifying two keys: throttle_condition and
11
- # backoff. Note that Tasks inherit conditions from their superclasses.
12
- #
13
- # @api private
14
- class_attribute :throttle_conditions, default: []
15
-
16
- class << self
17
- # Finds a Task with the given name.
18
- #
19
- # @param name [String] the name of the Task to be found.
20
- #
21
- # @return [Task] the Task with the given name.
22
- #
23
- # @raise [NotFoundError] if a Task with the given name does not exist.
24
- def named(name)
25
- task = name.safe_constantize
26
- raise NotFoundError.new("Task #{name} not found.", name) unless task
27
- unless task.is_a?(Class) && task < Task
28
- raise NotFoundError.new("#{name} is not a Task.", name)
29
- end
30
- task
31
- end
32
-
33
- # Returns a list of concrete classes that inherit from the Task
34
- # superclass.
35
- #
36
- # @return [Array<Class>] the list of classes.
37
- def available_tasks
38
- load_constants
39
- descendants
40
- end
41
-
42
- # Make this Task a task that handles CSV.
43
- #
44
- # An input to upload a CSV will be added in the form to start a Run. The
45
- # collection and count method are implemented.
46
- def csv_collection
47
- if !defined?(ActiveStorage) || !ActiveStorage::Attachment.table_exists?
48
- raise NotImplementedError, "Active Storage needs to be installed\n"\
49
- "To resolve this issue run: bin/rails active_storage:install"
50
- end
51
- include(CsvCollection)
52
- end
53
-
54
- # Processes one item.
55
- #
56
- # Especially useful for tests.
57
- #
58
- # @param item the item to process.
59
- def process(item)
60
- new.process(item)
61
- end
62
-
63
- # Returns the collection for this Task.
64
- #
65
- # Especially useful for tests.
66
- #
67
- # @return the collection.
68
- def collection
69
- new.collection
70
- end
71
-
72
- # Returns the count of items for this Task.
73
- #
74
- # Especially useful for tests.
75
- #
76
- # @return the count of items.
77
- def count
78
- new.count
79
- end
80
-
81
- # Add a condition under which this Task will be throttled.
82
- #
83
- # @param backoff [ActiveSupport::Duration] optionally, a custom backoff
84
- # can be specified. This is the time to wait before retrying the Task.
85
- # If no value is specified, it defaults to 30 seconds.
86
- # @yieldreturn [Boolean] where the throttle condition is being met,
87
- # indicating that the Task should throttle.
88
- def throttle_on(backoff: 30.seconds, &condition)
89
- self.throttle_conditions += [
90
- { throttle_on: condition, backoff: backoff },
91
- ]
92
- end
93
-
94
- private
95
-
96
- def load_constants
97
- namespace = MaintenanceTasks.tasks_module.safe_constantize
98
- return unless namespace
99
- namespace.constants.map { |constant| namespace.const_get(constant) }
100
- end
101
- end
102
-
103
- # Placeholder method to raise in case a subclass fails to implement the
104
- # expected instance method.
105
- #
106
- # @raise [NotImplementedError] with a message advising subclasses to
107
- # implement an override for this method.
108
- def collection
109
- raise NoMethodError, "#{self.class.name} must implement `collection`."
110
- end
111
-
112
- # Placeholder method to raise in case a subclass fails to implement the
113
- # expected instance method.
114
- #
115
- # @param _item [Object] the current item from the enumerator being iterated.
116
- #
117
- # @raise [NotImplementedError] with a message advising subclasses to
118
- # implement an override for this method.
119
- def process(_item)
120
- raise NoMethodError, "#{self.class.name} must implement `process`."
121
- end
122
-
123
- # Total count of iterations to be performed.
124
- #
125
- # Tasks override this method to define the total amount of iterations
126
- # expected at the start of the run. Return +nil+ if the amount is
127
- # undefined, or counting would be prohibitive for your database.
128
- #
129
- # @return [Integer, nil]
130
- def count
131
- end
132
- end
133
- end
@@ -1,16 +0,0 @@
1
- <h5 class="title is-5">
2
- <%= time_tag run.created_at, title: run.created_at %>
3
- <%= status_tag run.status if with_status %>
4
- </h5>
5
-
6
- <%= progress run %>
7
-
8
- <div class="content">
9
- <%= render "maintenance_tasks/runs/info/#{run.status}", run: run %>
10
- </div>
11
-
12
- <% if run.csv_file.present? %>
13
- <div class="block">
14
- <%= link_to('Download CSV', csv_file_download_path(run)) %>
15
- </div>
16
- <% end %>