maintenance_tasks 1.4.0 → 1.5.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: 6c3c4c94cf355432e0d558e68bfc3f275972164c8ed932d2505b7c6450f0d124
4
- data.tar.gz: 1b80ad4b58b9546d5ab2af77d2d0e64f8bd8b72dc6641ff445d33a67dae03860
3
+ metadata.gz: 8c13ec8d79682d304378d636955e9726cd1d67ebb167a549a2d6479f7eea6712
4
+ data.tar.gz: bf7026b08f0f442c3c074118dfca1cbae4babd7d234b97dc63cf66cdf94db67b
5
5
  SHA512:
6
- metadata.gz: 7402e24bfbc370c6af54b441d2b1050f252ee44f51ab11612875fed7fa6822645420422dc33405b1665596e66f85f8fe1f8b1e443d023d451a626913afe6dc98
7
- data.tar.gz: 8f4666aba4abc6f01d77b238de6b6d511d24a5d4932f5ec2499f0e91faefe2e8a3b18435109864c821495b2efde464dd3212a76eae5276b4e622eb1cb6f7da3c
6
+ metadata.gz: 3b41ee8a4ccaf28d590d7acd2a81fd5123dd3e81b552454082313d3a183b5840eb3ff130ab6c0a40c3e05112899680cee03bbec74c39e11bf0f91dff9955edb1
7
+ data.tar.gz: 42321e823247c83d58ead579070a5b007c7c0089601c7bcf587af311be715eb791102b94c2fdff513010816977c4c318297bb9f946726b3bd08066bc0ce295b2
data/README.md CHANGED
@@ -537,6 +537,23 @@ MaintenanceTasks.active_storage_service = :internal
537
537
  There is no need to configure this option if your application uses only one
538
538
  storage service per environment.
539
539
 
540
+ #### Customizing the backtrace cleaner
541
+
542
+ `MaintenanceTasks.backtrace_cleaner` can be configured to specify a backtrace
543
+ cleaner to use when a Task errors and the backtrace is cleaned and persisted.
544
+ An `ActiveSupport::BacktraceCleaner` should be used.
545
+
546
+ ```ruby
547
+ # config/initializers/maintenance_tasks.rb
548
+ cleaner = ActiveSupport::BacktraceCleaner.new
549
+ cleaner.add_silencer { |line| line =~ /ignore_this_dir/ }
550
+
551
+ MaintenanceTasks.backtrace_cleaner = cleaner
552
+ ```
553
+
554
+ If none is specified, the default `Rails.backtrace_cleaner` will be used to
555
+ clean backtraces.
556
+
540
557
  ## Upgrading
541
558
 
542
559
  Use bundler to check for and upgrade to newer versions. After installing a new
@@ -548,6 +565,16 @@ $ bin/rails generate maintenance_tasks:install
548
565
 
549
566
  This ensures that new migrations are installed and run as well.
550
567
 
568
+ **What if I've deleted my previous Maintenance Task migrations?**
569
+
570
+ The install command will attempt to reinstall these old migrations and migrating
571
+ the database will cause problems. Use `bin/rails generate maintenance_tasks:install:migrations`
572
+ to copy the gem's migrations to your `db/migrate` folder. Check the release
573
+ notes to see if any new migrations were added since your last gem upgrade.
574
+ Ensure that these are kept, but remove any migrations that already ran.
575
+
576
+ Run the migrations using `bin/rails db:migrate`.
577
+
551
578
  ## Contributing
552
579
 
553
580
  Would you like to report an issue or contribute with code? We accept issues and
@@ -564,6 +591,7 @@ are merged.
564
591
  Once a release is ready, follow these steps:
565
592
 
566
593
  * Update `spec.version` in `maintenance_tasks.gemspec`.
594
+ * Run `bundle install` to bump the `Gemfile.lock` version of the gem.
567
595
  * Open a PR and merge on approval.
568
596
  * Deploy via [Shipit][shipit] and see the new version on
569
597
  <https://rubygems.org/gems/maintenance_tasks>.
@@ -93,7 +93,6 @@ module MaintenanceTasks
93
93
  if @task.respond_to?(:csv_content=)
94
94
  @task.csv_content = @run.csv_file.download
95
95
  end
96
- @run.job_id = job_id
97
96
 
98
97
  @run.running! unless @run.stopping?
99
98
 
@@ -27,6 +27,7 @@ module MaintenanceTasks
27
27
  ]
28
28
  COMPLETED_STATUSES = [:succeeded, :errored, :cancelled]
29
29
  COMPLETED_RUNS_LIMIT = 10
30
+ STUCK_TASK_TIMEOUT = 5.minutes
30
31
 
31
32
  enum status: STATUSES.to_h { |status| [status, status.to_s] }
32
33
 
@@ -90,7 +91,7 @@ module MaintenanceTasks
90
91
  status: :errored,
91
92
  error_class: error.class.to_s,
92
93
  error_message: error.message,
93
- backtrace: Rails.backtrace_cleaner.clean(error.backtrace),
94
+ backtrace: MaintenanceTasks.backtrace_cleaner.clean(error.backtrace),
94
95
  ended_at: Time.now,
95
96
  )
96
97
  end
@@ -190,7 +191,7 @@ module MaintenanceTasks
190
191
  #
191
192
  # @return [Boolean] whether the Run is stuck.
192
193
  def stuck?
193
- cancelling? && updated_at <= 5.minutes.ago
194
+ cancelling? && updated_at <= STUCK_TASK_TIMEOUT.ago
194
195
  end
195
196
 
196
197
  # Performs validation on the presence of a :csv_file attachment.
@@ -51,17 +51,18 @@ module MaintenanceTasks
51
51
  run = Run.active.find_by(task_name: name) ||
52
52
  Run.new(task_name: name, arguments: arguments)
53
53
  run.csv_file.attach(csv_file) if csv_file
54
-
55
- run.enqueued!
56
- enqueue(run)
54
+ job = MaintenanceTasks.job.constantize.new(run)
55
+ run.job_id = job.job_id
57
56
  yield run if block_given?
57
+ run.enqueued!
58
+ enqueue(run, job)
58
59
  Task.named(name)
59
60
  end
60
61
 
61
62
  private
62
63
 
63
- def enqueue(run)
64
- unless MaintenanceTasks.job.constantize.perform_later(run)
64
+ def enqueue(run, job)
65
+ unless job.enqueue
65
66
  raise "The job to perform #{run.task_name} could not be enqueued. "\
66
67
  "Enqueuing has been prevented by a callback."
67
68
  end
@@ -40,7 +40,7 @@ module MaintenanceTasks
40
40
  def available_tasks
41
41
  task_names = Task.available_tasks.map(&:name)
42
42
  available_task_runs = Run.where(task_name: task_names)
43
- last_runs = Run.where(
43
+ last_runs = Run.with_attached_csv.where(
44
44
  id: available_task_runs.select("MAX(id) as id").group(:task_name)
45
45
  )
46
46
 
@@ -48,9 +48,8 @@ module MaintenanceTasks
48
48
  "errored",
49
49
  ],
50
50
  # paused -> enqueued occurs when the task is resumed after being paused.
51
- # paused -> cancelling when the user cancels the task after it is paused.
52
51
  # paused -> cancelled when the user cancels the task after it is paused.
53
- "paused" => ["enqueued", "cancelling", "cancelled"],
52
+ "paused" => ["enqueued", "cancelled"],
54
53
  # interrupted -> running occurs when the task is resumed after being
55
54
  # interrupted by the job infrastructure.
56
55
  # interrupted -> pausing occurs when the task is paused by the user while
@@ -0,0 +1,22 @@
1
+ <% if run.arguments.present? %>
2
+ <div class="table-container">
3
+ <h6 class="title is-6">Arguments:</h6>
4
+ <table class="table">
5
+ <tbody>
6
+ <% run.arguments.each do |key, value| %>
7
+ <tr>
8
+ <td class="is-family-monospace"><%= key %></td>
9
+ <td>
10
+ <% next if value.nil? || value.empty? %>
11
+ <% if value.include?("\n") %>
12
+ <pre><%= value %><pre>
13
+ <% else %>
14
+ <code><%= value %><code>
15
+ <% end %>
16
+ </td>
17
+ </tr>
18
+ <% end %>
19
+ </tbody>
20
+ </table>
21
+ </div>
22
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if run.csv_file.present? %>
2
+ <div class="block">
3
+ <%= link_to("Download CSV", csv_file_download_path(run)) %>
4
+ </div>
5
+ <% end %>
@@ -1,3 +1,16 @@
1
1
  <div class="box">
2
- <%= render 'maintenance_tasks/runs/info', run: run, with_status: true %>
2
+ <h5 class="title is-5">
3
+ <%= time_tag run.created_at, title: run.created_at %>
4
+ <%= status_tag run.status %>
5
+ </h5>
6
+
7
+ <%= progress run %>
8
+
9
+ <div class="content">
10
+ <%= render "maintenance_tasks/runs/info/#{run.status}", run: run %>
11
+ </div>
12
+
13
+ <%= render "maintenance_tasks/runs/csv", run: run %>
14
+ <%= tag.hr if run.csv_file.present? && run.arguments.present? %>
15
+ <%= render "maintenance_tasks/runs/arguments", run: run %>
3
16
  </div>
@@ -3,8 +3,6 @@
3
3
  <%= time_ago run.ended_at %>.
4
4
  </p>
5
5
 
6
- </p>
7
-
8
6
  <div class="card">
9
7
  <header class="card-header">
10
8
  <p class="card-header-title">
@@ -1,5 +1,3 @@
1
- <p>
2
- <% if (time_to_completion = run.time_to_completion) %>
3
- <%= distance_of_time_in_words(time_to_completion).capitalize %> remaining.
4
- <% end %>
5
- </p>
1
+ <% if (time_to_completion = run.time_to_completion) %>
2
+ <p>Running for <%= time_running_in_words(run) %>. <%= distance_of_time_in_words(time_to_completion).capitalize %> remaining.</p>
3
+ <% end %>
@@ -4,5 +4,19 @@
4
4
  <%= status_tag(task.status) %>
5
5
  </h3>
6
6
 
7
- <%= render 'maintenance_tasks/runs/info', run: task.last_run, with_status: false if task.last_run %>
7
+ <% if (run = task.last_run) %>
8
+ <h5 class="title is-5">
9
+ <%= time_tag run.created_at, title: run.created_at %>
10
+ </h5>
11
+
12
+ <%= progress run %>
13
+
14
+ <div class="content">
15
+ <%= render "maintenance_tasks/runs/info/#{run.status}", run: run %>
16
+ </div>
17
+
18
+ <%= render "maintenance_tasks/runs/csv", run: run %>
19
+ <%= tag.hr if run.csv_file.present? && run.arguments.present? %>
20
+ <%= render "maintenance_tasks/runs/arguments", run: run %>
21
+ <% end %>
8
22
  </div>
@@ -4,10 +4,25 @@
4
4
  <%= @task %> <%= status_tag(@task.status) %>
5
5
  </h1>
6
6
 
7
- <%= render 'maintenance_tasks/runs/info', run: @task.last_run, with_status: false if @task.last_run %>
7
+ <% last_run = @task.last_run %>
8
+ <% if last_run %>
9
+ <h5 class="title is-5">
10
+ <%= time_tag last_run.created_at, title: last_run.created_at %>
11
+ </h5>
12
+
13
+ <%= progress last_run %>
14
+
15
+ <div class="content">
16
+ <%= render "maintenance_tasks/runs/info/#{last_run.status}", run: last_run %>
17
+ </div>
18
+
19
+ <%= render "maintenance_tasks/runs/csv", run: last_run %>
20
+ <%= tag.hr if last_run.csv_file.present? %>
21
+ <%= render "maintenance_tasks/runs/arguments", run: last_run %>
22
+ <%= tag.hr if last_run.arguments.present? %>
23
+ <% end %>
8
24
 
9
25
  <div class="buttons">
10
- <% last_run = @task.last_run %>
11
26
  <% if last_run.nil? || last_run.completed? %>
12
27
  <%= form_with url: run_task_path(@task), method: :put do |form| %>
13
28
  <% if @task.csv_task? %>
@@ -20,8 +35,12 @@
20
35
  <div class="block">
21
36
  <%= form.fields_for :task_arguments do |ff| %>
22
37
  <% @task.parameter_names.each do |parameter| %>
23
- <%= ff.label parameter, "#{parameter}: ", class: "label" %>
24
- <%= ff.text_area parameter, class: "textarea" %>
38
+ <div class="field">
39
+ <%= ff.label parameter, parameter, class: "label is-family-monospace" %>
40
+ <div class="control">
41
+ <%= ff.text_area parameter, class: "textarea" %>
42
+ </div>
43
+ </div>
25
44
  <% end %>
26
45
  <% end %>
27
46
  </div>
@@ -52,6 +52,16 @@ module MaintenanceTasks
52
52
  # app's config/storage.yml.
53
53
  mattr_accessor :active_storage_service
54
54
 
55
+ # @!attribute backtrace_cleaner
56
+ # @scope class
57
+ #
58
+ # The Active Support backtrace cleaner that will be used to clean the
59
+ # backtrace of a Task that errors.
60
+ #
61
+ # @return [ActiveSupport::BacktraceCleaner, nil] the backtrace cleaner to
62
+ # use when cleaning a Run's backtrace.
63
+ mattr_accessor :backtrace_cleaner
64
+
55
65
  # @private
56
66
  def self.error_handler
57
67
  return @error_handler if defined?(@error_handler)
@@ -11,6 +11,10 @@ module MaintenanceTasks
11
11
  eager_load! unless Rails.autoloaders.zeitwerk_enabled?
12
12
  end
13
13
 
14
+ initializer "maintenance_tasks.configs" do
15
+ MaintenanceTasks.backtrace_cleaner = Rails.backtrace_cleaner
16
+ end
17
+
14
18
  config.to_prepare do
15
19
  _ = TaskJobConcern # load this for JobIteration compatibility check
16
20
  unless Rails.autoloaders.zeitwerk_enabled?
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.0
4
+ version: 1.5.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-06-07 00:00:00.000000000 Z
11
+ date: 2021-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -108,7 +108,8 @@ files:
108
108
  - app/validators/maintenance_tasks/run_status_validator.rb
109
109
  - app/views/layouts/maintenance_tasks/_navbar.html.erb
110
110
  - app/views/layouts/maintenance_tasks/application.html.erb
111
- - app/views/maintenance_tasks/runs/_info.html.erb
111
+ - app/views/maintenance_tasks/runs/_arguments.html.erb
112
+ - app/views/maintenance_tasks/runs/_csv.html.erb
112
113
  - app/views/maintenance_tasks/runs/_run.html.erb
113
114
  - app/views/maintenance_tasks/runs/info/_cancelled.html.erb
114
115
  - app/views/maintenance_tasks/runs/info/_cancelling.html.erb
@@ -142,7 +143,7 @@ homepage: https://github.com/Shopify/maintenance_tasks
142
143
  licenses:
143
144
  - MIT
144
145
  metadata:
145
- source_code_uri: https://github.com/Shopify/maintenance_tasks/tree/v1.4.0
146
+ source_code_uri: https://github.com/Shopify/maintenance_tasks/tree/v1.5.0
146
147
  allowed_push_host: https://rubygems.org
147
148
  post_install_message:
148
149
  rdoc_options: []
@@ -159,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
159
160
  - !ruby/object:Gem::Version
160
161
  version: '0'
161
162
  requirements: []
162
- rubygems_version: 3.2.17
163
+ rubygems_version: 3.2.20
163
164
  signing_key:
164
165
  specification_version: 4
165
166
  summary: A Rails engine for queuing and managing maintenance tasks
@@ -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 %>