maintenance_tasks 2.7.0 → 2.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2869ba1c05cb80edb54803f50037bb45b388a5489bec724a79617d2890e78fdc
4
- data.tar.gz: 5a936d433f102642e972f4c04e7fd96817193f0075b252e942c1ff86bb6a0e06
3
+ metadata.gz: b984293788834b153823e857dad5020b8cca1902037c97fd158401c1da3cfee3
4
+ data.tar.gz: 0c079b820fbfd3d7e26e7c19585ac8b41199de92f7a71e671a63c7db46b60d06
5
5
  SHA512:
6
- metadata.gz: 5e054a909fd05bacc7482caa7cba9cc69ed15850bdec1e0bbf09466426ad6bcfadd12c086a4efe185eb5be1edc40b3fbacaca34b555fac39fa0dcfac2df50405
7
- data.tar.gz: fa1c8baed4e9cc6b34acd03e9c16ef2266da288293da212fb96c03d6a6be2d87fb5599e167e4d629e80f16a80127b611ffe6b8895867958a92675dca06457e48
6
+ metadata.gz: f43e5c6535246bf7259bb21cfd1eb3f48f356a9f1f2e83fea19096cdff8610a601d4ea96b623d63bbecbaa593d1022a34fd16210896f83852f64c3e3bf003b41
7
+ data.tar.gz: a506d5e89ec233e60a59c428801d8e2e79a57f6604f8ab9cf97882b71bf69f4304f7d1fa53ac33ecd4ab5bb76f9de3774cbf9d1bfdd7cdff52af1849379b7e6d
data/README.md CHANGED
@@ -156,6 +156,32 @@ module Maintenance
156
156
  end
157
157
  ```
158
158
 
159
+ #### Customizing the Batch Size
160
+
161
+ When processing records from an Active Record Relation, records are fetched in
162
+ batches internally, and then each record is passed to the `#process` method.
163
+ Maintenance Tasks will query the database to fetch records in batches of 100 by
164
+ default, but the batch size can be modified using the `collection_batch_size` macro:
165
+
166
+ ```ruby
167
+ # app/tasks/maintenance/update_posts_task.rb
168
+
169
+ module Maintenance
170
+ class UpdatePostsTask < MaintenanceTasks::Task
171
+ # Fetch records in batches of 1000
172
+ collection_batch_size(1000)
173
+
174
+ def collection
175
+ Post.all
176
+ end
177
+
178
+ def process(post)
179
+ post.update!(content: "New content!")
180
+ end
181
+ end
182
+ end
183
+ ```
184
+
159
185
  ### Creating a CSV Task
160
186
 
161
187
  You can also write a Task that iterates on a CSV file. Note that writing CSV
@@ -497,7 +523,10 @@ end
497
523
 
498
524
  ### Subscribing to instrumentation events
499
525
 
500
- If you are interested in actioning a specific task event, please refer to the [Using Task Callbacks](#using-task-callbacks) section below. However, if you want to subscribe to all events, irrespective of the task, you can use the following Active Support notifications:
526
+ If you are interested in actioning a specific task event, please refer to the
527
+ [Using Task Callbacks](#using-task-callbacks) section below. However, if you
528
+ want to subscribe to all events, irrespective of the task, you can use the
529
+ following Active Support notifications:
501
530
 
502
531
  ```ruby
503
532
  enqueued.maintenance_tasks # This event is published when a task has been enqueued by the user.
@@ -507,7 +536,8 @@ paused.maintenance_tasks # This event is published when a task is paused by
507
536
  errored.maintenance_tasks # This event is published when the task's code produces an unhandled exception.
508
537
  ```
509
538
 
510
- These notifications offer a way to monitor the lifecycle of maintenance tasks in your application.
539
+ These notifications offer a way to monitor the lifecycle of maintenance tasks in
540
+ your application.
511
541
 
512
542
  Usage example:
513
543
 
@@ -723,9 +753,9 @@ end
723
753
  ### Writing tests for a Task that uses a custom enumerator
724
754
 
725
755
  Tests for tasks that use custom enumerators need to instantiate the task class
726
- in order to call `#build_enumerator`. Once the task instance is set up, validate
727
- that `#build_enumerator` returns an enumerator yielding pairs of [item, cursor]
728
- as expected.
756
+ in order to call `#enumerator_builder`. Once the task instance is set up,
757
+ validate that `#enumerator_builder` returns an enumerator yielding pairs of
758
+ `[item, cursor]` as expected.
729
759
 
730
760
  ```ruby
731
761
  # test/tasks/maintenance/custom_enumerating_task.rb
@@ -738,8 +768,8 @@ module Maintenance
738
768
  @task = CustomEnumeratingTask.new
739
769
  end
740
770
 
741
- test "#build_enumerator returns enumerator yielding pairs of [item, cursor]" do
742
- enum = @task.build_enumerator(cursor: 0)
771
+ test "#enumerator_builder returns enumerator yielding pairs of [item, cursor]" do
772
+ enum = @task.enumerator_builder(cursor: 0)
743
773
  expected_items = [:b, :c]
744
774
 
745
775
  assert_equal 2, enum.size
@@ -32,13 +32,16 @@ module MaintenanceTasks
32
32
 
33
33
  def build_enumerator(_run, cursor:)
34
34
  cursor ||= @run.cursor
35
+ self.cursor_position = cursor
35
36
  @collection_enum = @task.enumerator_builder(cursor: cursor)
36
37
 
37
38
  @collection_enum ||= case (collection = @task.collection)
38
39
  when :no_collection
39
40
  enumerator_builder.build_once_enumerator(cursor: nil)
40
41
  when ActiveRecord::Relation
41
- enumerator_builder.active_record_on_records(collection, cursor: cursor, columns: @task.cursor_columns)
42
+ options = { cursor: cursor, columns: @task.cursor_columns }
43
+ options[:batch_size] = @task.active_record_enumerator_batch_size if @task.active_record_enumerator_batch_size
44
+ enumerator_builder.active_record_on_records(collection, **options)
42
45
  when ActiveRecord::Batches::BatchEnumerator
43
46
  if collection.start || collection.finish
44
47
  raise ArgumentError, <<~MSG.squish
@@ -163,6 +166,7 @@ module MaintenanceTasks
163
166
  end
164
167
 
165
168
  def on_error(error)
169
+ task_context = {}
166
170
  @ticker.persist if defined?(@ticker)
167
171
 
168
172
  if defined?(@run)
@@ -174,8 +178,6 @@ module MaintenanceTasks
174
178
  started_at: @run.started_at,
175
179
  ended_at: @run.ended_at,
176
180
  }
177
- else
178
- task_context = {}
179
181
  end
180
182
  errored_element = @errored_element if defined?(@errored_element)
181
183
  ensure
@@ -18,6 +18,12 @@ module MaintenanceTasks
18
18
  # @api private
19
19
  class_attribute :throttle_conditions, default: []
20
20
 
21
+ # The number of active records to fetch in a single query when iterating
22
+ # over an Active Record collection task.
23
+ #
24
+ # @api private
25
+ class_attribute :active_record_enumerator_batch_size
26
+
21
27
  # @api private
22
28
  class_attribute :collection_builder_strategy, default: NullCollectionBuilder.new
23
29
 
@@ -79,6 +85,7 @@ module MaintenanceTasks
79
85
  end
80
86
 
81
87
  csv_options[:headers] = true unless csv_options.key?(:headers)
88
+ csv_options[:encoding] ||= Encoding.default_external
82
89
  self.collection_builder_strategy = if in_batches
83
90
  BatchCsvCollectionBuilder.new(in_batches, **csv_options)
84
91
  else
@@ -137,6 +144,14 @@ module MaintenanceTasks
137
144
  self.throttle_conditions += [{ throttle_on: condition, backoff: backoff_as_proc }]
138
145
  end
139
146
 
147
+ # Limit the number of records that will be fetched in a single query when
148
+ # iterating over an Active Record collection task.
149
+ #
150
+ # @param size [Integer] the number of records to fetch in a single query.
151
+ def collection_batch_size(size)
152
+ self.active_record_enumerator_batch_size = size
153
+ end
154
+
140
155
  # Initialize a callback to run after the task starts.
141
156
  #
142
157
  # @param filter_list apply filters to the callback
@@ -44,7 +44,7 @@
44
44
 
45
45
  <h4 class="title is-4">Active Runs</h4>
46
46
 
47
- <%= render @task.active_runs %>
47
+ <%= render partial: "maintenance_tasks/runs/run", collection: @task.active_runs %>
48
48
  <% end %>
49
49
 
50
50
  <% if @runs_page.records.present? %>
@@ -52,7 +52,7 @@
52
52
 
53
53
  <h4 class="title is-4">Previous Runs</h4>
54
54
 
55
- <%= render @runs_page.records %>
55
+ <%= render partial: "maintenance_tasks/runs/run", collection: @runs_page.records %>
56
56
 
57
57
  <%= link_to "Next page", task_path(@task, cursor: @runs_page.next_cursor) unless @runs_page.last? %>
58
58
  <% end %>
@@ -10,7 +10,7 @@ module MaintenanceTasks
10
10
 
11
11
  # Mounts the engine in the host application's config/routes.rb
12
12
  def mount_engine
13
- route("mount MaintenanceTasks::Engine => \"/maintenance_tasks\"")
13
+ route("mount MaintenanceTasks::Engine, at: \"/maintenance_tasks\"")
14
14
  end
15
15
 
16
16
  # Copies engine migrations to host application and migrates the database
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: 2.7.0
4
+ version: 2.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify Engineering
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-04-16 00:00:00.000000000 Z
11
+ date: 2024-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '6.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: csv
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: job-iteration
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -94,7 +108,7 @@ dependencies:
94
108
  - - ">="
95
109
  - !ruby/object:Gem::Version
96
110
  version: 2.6.2
97
- description:
111
+ description:
98
112
  email: gems@shopify.com
99
113
  executables:
100
114
  - maintenance_tasks
@@ -171,9 +185,9 @@ homepage: https://github.com/Shopify/maintenance_tasks
171
185
  licenses:
172
186
  - MIT
173
187
  metadata:
174
- source_code_uri: https://github.com/Shopify/maintenance_tasks/tree/v2.7.0
188
+ source_code_uri: https://github.com/Shopify/maintenance_tasks/tree/v2.8.0
175
189
  allowed_push_host: https://rubygems.org
176
- post_install_message:
190
+ post_install_message:
177
191
  rdoc_options: []
178
192
  require_paths:
179
193
  - lib
@@ -188,8 +202,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
188
202
  - !ruby/object:Gem::Version
189
203
  version: '0'
190
204
  requirements: []
191
- rubygems_version: 3.5.9
192
- signing_key:
205
+ rubygems_version: 3.5.17
206
+ signing_key:
193
207
  specification_version: 4
194
208
  summary: A Rails engine for queuing and managing maintenance tasks
195
209
  test_files: []