mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-03 16:44:58 +08:00
Scheduled problem checks with multiple targets are not honouring the `run_every` configuration. For checks with multiple targets, all targets are checked in a single instance of the problem check. However, we have one problem check tracker per target. This mismatch results in the `#ready_to_run?` method always creating a tracker with no target when being checked. This commit fixes that by: **Expect checks to operate on a single target.** This change makes it so that instances of a `ProblemCheck` class are initialized with a target. So instead of 1-N we now have an N-N relationship between checks and trackers. Each instance can access their `target` through an attribute of the same name. This also means problem checks are back to returning a singular `Problem` or `nil`, instead of `[Problem]` or `[]`. For scheduled checks, this means that `ScheduleProblemChecks` now enqueues `N` jobs (where `N` is the number of targets) per check instead of `1` job per check. **Update existing targeted checks to operate on a single target.** This is essentially just removing the loop inside the check.
165 lines
4.5 KiB
Ruby
165 lines
4.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
RSpec.describe Jobs::RunProblemChecks do
|
|
around do |example|
|
|
ProblemCheck::ScheduledCheck =
|
|
Class.new(ProblemCheck) do
|
|
self.perform_every = 30.minutes
|
|
|
|
def call = []
|
|
end
|
|
|
|
ProblemCheck::NonScheduledCheck = Class.new(ProblemCheck) { def call = [] }
|
|
|
|
ProblemCheck::DisabledCheck =
|
|
Class.new(ProblemCheck) do
|
|
self.perform_every = 30.minutes
|
|
self.enabled = false
|
|
|
|
def call = []
|
|
end
|
|
|
|
ProblemCheck::MultiTargetCheck =
|
|
Class.new(ProblemCheck) do
|
|
self.perform_every = 30.minutes
|
|
self.targets = -> { %w[foo bar] }
|
|
end
|
|
|
|
stub_const(
|
|
ProblemCheck,
|
|
"CORE_PROBLEM_CHECKS",
|
|
[
|
|
ProblemCheck::ScheduledCheck,
|
|
ProblemCheck::NonScheduledCheck,
|
|
ProblemCheck::DisabledCheck,
|
|
ProblemCheck::MultiTargetCheck,
|
|
],
|
|
&example
|
|
)
|
|
|
|
ProblemCheck.send(:remove_const, "ScheduledCheck")
|
|
ProblemCheck.send(:remove_const, "NonScheduledCheck")
|
|
ProblemCheck.send(:remove_const, "DisabledCheck")
|
|
ProblemCheck.send(:remove_const, "MultiTargetCheck")
|
|
end
|
|
|
|
context "when a tracker hasn't been created yet" do
|
|
it "still schedules checks" do
|
|
expect_enqueued_with(
|
|
job: :run_problem_check,
|
|
args: {
|
|
check_identifier: "scheduled_check",
|
|
target: ProblemCheck::NO_TARGET,
|
|
},
|
|
) { described_class.new.execute([]) }
|
|
end
|
|
end
|
|
|
|
context "when the tracker determines the check is ready to run" do
|
|
before do
|
|
ProblemCheckTracker.create!(identifier: "scheduled_check", next_run_at: 5.minutes.ago)
|
|
end
|
|
|
|
it "schedules the individual scheduled checks" do
|
|
expect_enqueued_with(
|
|
job: :run_problem_check,
|
|
args: {
|
|
check_identifier: "scheduled_check",
|
|
target: ProblemCheck::NO_TARGET,
|
|
},
|
|
) { described_class.new.execute([]) }
|
|
end
|
|
end
|
|
|
|
context "when the tracker determines the check shouldn't run yet" do
|
|
before do
|
|
ProblemCheckTracker.create!(identifier: "scheduled_check", next_run_at: 5.minutes.from_now)
|
|
end
|
|
|
|
it "does not schedule any check" do
|
|
expect_not_enqueued_with(
|
|
job: :run_problem_check,
|
|
args: {
|
|
check_identifier: "scheduled_check",
|
|
},
|
|
) { described_class.new.execute([]) }
|
|
end
|
|
end
|
|
|
|
context "when dealing with a non-scheduled check" do
|
|
before { ProblemCheckTracker.create!(identifier: "non_scheduled_check", next_run_at: nil) }
|
|
|
|
it "does not schedule any check" do
|
|
expect_not_enqueued_with(
|
|
job: :run_problem_check,
|
|
args: {
|
|
check_identifier: "non_scheduled_check",
|
|
},
|
|
) { described_class.new.execute([]) }
|
|
end
|
|
end
|
|
|
|
context "when dealing with a disabled check" do
|
|
before { ProblemCheckTracker.create!(identifier: "disabled_check", next_run_at: nil) }
|
|
|
|
it "does not schedule any check" do
|
|
expect_not_enqueued_with(
|
|
job: :run_problem_check,
|
|
args: {
|
|
check_identifier: "disabled_check",
|
|
},
|
|
) { described_class.new.execute([]) }
|
|
end
|
|
end
|
|
|
|
context "when dealing with an uninstalled check" do
|
|
before { ProblemCheckTracker.create!(identifier: "uninstalled_check", next_run_at: nil) }
|
|
|
|
it "does not schedule any check" do
|
|
expect_not_enqueued_with(
|
|
job: :run_problem_check,
|
|
args: {
|
|
check_identifier: "uninstalled_check",
|
|
},
|
|
) { described_class.new.execute([]) }
|
|
end
|
|
end
|
|
|
|
context "when dealing with a multi-target check" do
|
|
it "schedules one check per target" do
|
|
expect_enqueued_with(
|
|
job: :run_problem_check,
|
|
args: {
|
|
check_identifier: "multi_target_check",
|
|
target: "foo",
|
|
},
|
|
) { described_class.new.execute([]) }
|
|
|
|
expect_enqueued_with(
|
|
job: :run_problem_check,
|
|
args: {
|
|
check_identifier: "multi_target_check",
|
|
target: "bar",
|
|
},
|
|
) { described_class.new.execute([]) }
|
|
end
|
|
|
|
it "creates a problem tracker for each target" do
|
|
expect { described_class.new.execute([]) }.to change {
|
|
ProblemCheckTracker.where(
|
|
identifier: "multi_target_check",
|
|
target: ProblemCheck::MultiTargetCheck.targets.call,
|
|
).count
|
|
}.by(2)
|
|
end
|
|
|
|
it "does not create any no-target tracker" do
|
|
expect { described_class.new.execute([]) }.not_to change {
|
|
ProblemCheckTracker.where(
|
|
identifier: "multi_target_check",
|
|
target: ProblemCheck::NO_TARGET,
|
|
).count
|
|
}
|
|
end
|
|
end
|
|
end
|