Skip to content

Commit f6403aa

Browse files
committed
Support both global and per Application/Server backtrace cleaners
* (Hopefully) addressed @rosa's feedback on project style, code quality, and implementation requirements * Updated the design to support both a global MissionControl::Jobs wide backtrace cleaner and Application/Server specific backtrace cleaners * With this commit, the implementation relies less on jobs_helper.rb and more on a new before_action in the jobs_controller. * Added more UI testing for compleness
1 parent 2277373 commit f6403aa

File tree

10 files changed

+107
-26
lines changed

10 files changed

+107
-26
lines changed

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ Besides `base_controller_class`, you can also set the following for `MissionCont
5757
- `internal_query_count_limit`: in count queries, the maximum number of records that will be counted if the adapter needs to limit these queries. True counts above this number will be returned as `INFINITY`. This keeps count queries fast—defaults to `500,000`
5858
- `scheduled_job_delay_threshold`: the time duration before a scheduled job is considered delayed. Defaults to `1.minute` (a job is considered delayed if it hasn't transitioned from the `scheduled` status 1 minute after the scheduled time).
5959
- `show_console_help`: whether to show the console help. If you don't want the console help message, set this to `false`—defaults to `true`.
60+
- `backtrace_cleaner`: a backtrace cleaner used for optionally filtering backtraces on the Failed Jobs detail page. Defaults to `Rails::BacktraceCleaner.new`. See the [Advanced configuration](#advanced-configuration) section for how to configure/override this setting on a per application/server basis.
6061

6162
This library extends Active Job with a querying interface and the following setting:
6263
- `config.active_job.default_page_size`: the internal batch size that Active Job will use when sending queries to the underlying adapter and the batch size for the bulk operations defined above—defaults to `1000`.
@@ -107,7 +108,24 @@ SERVERS_BY_APP.each do |app, servers|
107108
ActiveJob::QueueAdapters::SolidQueueAdapter.new
108109
end
109110

110-
[ server, queue_adapter ]
111+
# Default:
112+
#
113+
# @return Array<String, ActiveJob::QueueAdapters::Base)
114+
# An array where:
115+
# * the String represents the symbolic name for this server within the UI
116+
# * ActiveJob::QueueAdapters::Base adapter instance used to access this Application Server/Service
117+
[ server, queue_adapter ]
118+
119+
# Optional return formats:
120+
#
121+
# @return Array<String, Array<ActiveJob::QueueAdapters::Base>>
122+
# * This is equivalent, and behaves identically to, the format the default format above.
123+
# [ server, [ queue_adapter ]] # without optional backtrace cleaner
124+
#
125+
# @return Array<String, Array<ActiveJob::QueueAdapters::Base, ActiveSupport::BacktraceCleaner>>
126+
# * This format adds an optional ActiveSupport::BacktraceCleaner to override the system wide
127+
# backtrace cleaner for *this* Application Server/Service.
128+
# [ server, [ queue_adapter, BacktraceCleaner.new ]] # with optional backtrace cleaner
111129
end.to_h
112130

113131
MissionControl::Jobs.applications.add(app, queue_adapters_by_name)

app/controllers/mission_control/jobs/jobs_controller.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ class MissionControl::Jobs::JobsController < MissionControl::Jobs::ApplicationCo
22
include MissionControl::Jobs::JobScoped, MissionControl::Jobs::JobFilters
33

44
skip_before_action :set_job, only: :index
5+
before_action :set_backtrace_cleaner, only: :show
56

67
def index
78
@job_class_names = jobs_with_status.job_class_names
@@ -15,6 +16,7 @@ def show
1516
end
1617

1718
private
19+
1820
def jobs_relation
1921
filtered_jobs
2022
end
@@ -36,4 +38,12 @@ def filtered_jobs
3638
def jobs_status
3739
params[:status].presence&.inquiry
3840
end
41+
42+
def set_backtrace_cleaner
43+
@backtrace_cleaner = @application.servers[server_id]&.backtrace_cleaner
44+
end
45+
46+
def server_id
47+
params[:server_id]
48+
end
3949
end

app/helpers/mission_control/jobs/jobs_helper.rb

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ def failed_job_error(job)
1111
"#{job.last_execution_error.error_class}: #{job.last_execution_error.message}"
1212
end
1313

14-
def backtrace_cleaner = Rails.backtrace_cleaner
15-
16-
def backtrace_cleaner? = backtrace_cleaner.present?
17-
18-
def should_clean_backtrace? = params["clean_backtrace"] == "true"
19-
20-
def failed_job_backtrace(job, clean: false)
21-
return job.last_execution_error.backtrace.join("\n") if !clean || !backtrace_cleaner?
14+
def clean_backtrace?
15+
params["clean_backtrace"] == "true"
16+
end
2217

23-
backtrace_cleaner.clean(job.last_execution_error.backtrace).join("\n")
18+
def failed_job_backtrace(job)
19+
if clean_backtrace? && @backtrace_cleaner
20+
@backtrace_cleaner.clean(job.last_execution_error.backtrace).join("\n")
21+
else
22+
job.last_execution_error.backtrace.join("\n")
23+
end
2424
end
2525

2626
def attribute_names_for_job_status(status)

app/views/mission_control/jobs/jobs/_error_information.html.erb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
</tbody>
1515
</table>
1616

17-
<%= render "mission_control/jobs/jobs/failed/backtrace_toggle", application: @application, job: @job if backtrace_cleaner? %>
17+
<% if @backtrace_cleaner %>
18+
<%= render "mission_control/jobs/jobs/failed/backtrace_toggle", application: @application, job: job %>
19+
<% end %>
1820

19-
<pre class="is-family-monospace mb-4 backtrace-selector"><%= failed_job_backtrace(job, clean: should_clean_backtrace?) %></pre>
21+
<pre class="is-family-monospace mb-4 backtrace-content"><%= failed_job_backtrace(job) %></pre>
2022
<% end %>

app/views/mission_control/jobs/jobs/failed/_backtrace_toggle.html.erb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
<%# locals: (application:, job:) %>
2+
13
<div class="is-flex is-justify-content-flex-end mb-2 mr-2 backtrace-toggle-selector">
24
<div class="tabs is-toggle is-toggle-rounded is-small">
35
<ul>
4-
<li class="<%= 'is-active' if should_clean_backtrace? %>">
5-
<%= link_to("Clean", application_job_path(application, job.job_id, clean_backtrace: true)) %>
6+
<li class="<%= class_names('backtrace-clean-link', 'is-active' => clean_backtrace?) %>">
7+
<%= link_to "Clean", application_job_path(application, job.job_id, clean_backtrace: true) %>
68
</li>
7-
<li class="<%= 'is-active' unless should_clean_backtrace? %>">
8-
<%= link_to("Full", application_job_path(application, job.job_id, clean_backtrace: false)) %>
9+
<li class="<%= class_names('backtrace-full-link', 'is-active' => !clean_backtrace?) %>">
10+
<%= link_to "Full", application_job_path(application, job.job_id, clean_backtrace: false) %>
911
</li>
1012
</ul>
1113
</div>

lib/mission_control/jobs.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@ module Jobs
1919
mattr_accessor :internal_query_count_limit, default: 500_000 # Hard limit to keep unlimited count queries fast enough
2020
mattr_accessor :show_console_help, default: true
2121
mattr_accessor :scheduled_job_delay_threshold, default: 1.minute
22-
mattr_accessor :backtrace_cleaner, default: proc { Rails.backtrace_cleaner }
22+
mattr_accessor :backtrace_cleaner
2323
end
2424
end

lib/mission_control/jobs/application.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ def initialize(name:)
1111

1212
def add_servers(queue_adapters_by_name)
1313
queue_adapters_by_name.each do |name, queue_adapter|
14-
servers << MissionControl::Jobs::Server.new(name: name.to_s, queue_adapter: queue_adapter, application: self)
14+
adapter, cleaner = queue_adapter
15+
cleaner ||= MissionControl::Jobs.backtrace_cleaner
16+
17+
servers << MissionControl::Jobs::Server.new(name: name.to_s, queue_adapter: adapter,
18+
backtrace_cleaner: cleaner, application: self)
1519
end
1620
end
1721
end

lib/mission_control/jobs/engine.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class Engine < ::Rails::Engine
1515

1616
config.before_initialize do
1717
config.mission_control.jobs.applications = MissionControl::Jobs::Applications.new
18+
config.mission_control.jobs.backtrace_cleaner ||= Rails::BacktraceCleaner.new
1819

1920
config.mission_control.jobs.each do |key, value|
2021
MissionControl::Jobs.public_send("#{key}=", value)

lib/mission_control/jobs/server.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ class MissionControl::Jobs::Server
44
include MissionControl::Jobs::IdentifiedByName
55
include Serializable, RecurringTasks, Workers
66

7-
attr_reader :name, :queue_adapter, :application
7+
attr_reader :name, :queue_adapter, :application, :backtrace_cleaner
88

9-
def initialize(name:, queue_adapter:, application:)
9+
def initialize(name:, queue_adapter:, application:, backtrace_cleaner:)
1010
super(name: name)
1111
@queue_adapter = queue_adapter
1212
@application = application
13+
@backtrace_cleaner = backtrace_cleaner
1314
end
1415

1516
def activating(&block)

test/system/show_failed_job_test.rb

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,47 @@ class ShowFailedJobsTest < ApplicationSystemTestCase
3030
assert_text /there are no failed jobs/i
3131
end
3232

33-
test "show backtrace cleaner buttons" do
33+
test "Has Clean/Full buttons when a backtrace cleaner is configured" do
3434
visit jobs_path(:failed)
35-
within_job_row /FailingJob\s*2/ do
35+
within_job_row(/FailingJob\s*2/) do
36+
click_on "RuntimeError: This always fails!"
37+
end
38+
39+
assert_selector ".backtrace-toggle-selector"
40+
end
41+
42+
test "Does not offer Clean/Full buttons when a backtrace cleaner is not configured" do
43+
setup do
44+
# grab the current state
45+
@backtrace_cleaner = MissionControl::Jobs.backtrace_cleaner
46+
@applications = MissionControl::Jobs.backtrace_cleaner
47+
48+
# reset the state
49+
MissionControl::Jobs.backtrace_cleaner = nil
50+
MissionControl::Jobs.applications = Applications.new
51+
52+
# Setup the application with what we had before *minus* a backtrace cleaner
53+
@applications.each do |application|
54+
MissionControl::Jobs.applications.add(application.name).tap do |it|
55+
application.servers.each do |server|
56+
it.add_servers(server.name, server.queue_adapter)
57+
end
58+
end
59+
end
60+
end
61+
62+
teardown do
63+
# reset back to the known state before the start of the test
64+
MissionControl::Jobs.backtrace_cleaner = @backtrace_cleaner
65+
MissionControl::Jobs.applications = @application
66+
end
67+
68+
visit jobs_path(:failed)
69+
within_job_row(/FailingJob\s*2/) do
3670
click_on "RuntimeError: This always fails!"
3771
end
3872

39-
assert_text /clean/i
73+
assert_no_selector ".backtrace-toggle-selector"
4074
end
4175

4276
test "click on 'clean' shows a backtrace cleaned by the Rails default backtrace cleaner" do
@@ -45,9 +79,18 @@ class ShowFailedJobsTest < ApplicationSystemTestCase
4579
click_on "RuntimeError: This always fails!"
4680
end
4781

48-
click_on "Clean"
49-
within ".backtrace-selector" do
50-
assert_no_selector "*"
82+
assert_selector ".backtrace-toggle-selector"
83+
84+
within ".backtrace-toggle-selector" do
85+
click_on "Clean"
5186
end
87+
88+
assert_selector "pre.backtrace-content", text: /.*/, visible: true
89+
90+
within ".backtrace-toggle-selector" do
91+
click_on "Full"
92+
end
93+
94+
assert_selector "pre.backtrace-content", text: /.*/, visible: true
5295
end
5396
end

0 commit comments

Comments
 (0)