2019-04-30 08:27:42 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2022-07-28 10:27:38 +08:00
|
|
|
RSpec.describe ::Jobs::Base do
|
2019-10-02 12:01:53 +08:00
|
|
|
class GoodJob < ::Jobs::Base
|
2014-02-21 13:05:19 +08:00
|
|
|
attr_accessor :count
|
|
|
|
def execute(args)
|
|
|
|
self.count ||= 0
|
|
|
|
self.count += 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-10-02 12:01:53 +08:00
|
|
|
class BadJob < ::Jobs::Base
|
2022-08-05 15:40:22 +08:00
|
|
|
class BadJobError < StandardError
|
|
|
|
end
|
|
|
|
|
2014-02-21 12:31:15 +08:00
|
|
|
attr_accessor :fail_count
|
|
|
|
|
|
|
|
def execute(args)
|
|
|
|
@fail_count ||= 0
|
|
|
|
@fail_count += 1
|
2022-08-05 15:40:22 +08:00
|
|
|
raise BadJobError
|
2014-02-21 12:31:15 +08:00
|
|
|
end
|
|
|
|
end
|
2015-02-10 04:47:46 +08:00
|
|
|
|
2014-02-21 13:05:19 +08:00
|
|
|
it 'handles correct jobs' do
|
|
|
|
job = GoodJob.new
|
|
|
|
job.perform({})
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(job.count).to eq(1)
|
2014-02-21 13:05:19 +08:00
|
|
|
end
|
2014-02-21 12:31:15 +08:00
|
|
|
|
|
|
|
it 'handles errors in multisite' do
|
2014-07-18 04:22:46 +08:00
|
|
|
RailsMultisite::ConnectionManagement.expects(:all_dbs).returns(['default', 'default', 'default'])
|
|
|
|
# one exception per database
|
2015-02-10 04:47:46 +08:00
|
|
|
Discourse.expects(:handle_job_exception).times(3)
|
2014-02-21 12:31:15 +08:00
|
|
|
|
2015-02-10 04:47:46 +08:00
|
|
|
bad = BadJob.new
|
2016-05-30 11:38:04 +08:00
|
|
|
expect { bad.perform({}) }.to raise_error(Jobs::HandledExceptionWrapper)
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(bad.fail_count).to eq(3)
|
2014-02-21 12:31:15 +08:00
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2022-08-05 15:40:22 +08:00
|
|
|
describe '#perform' do
|
|
|
|
context 'when a job raises an error' do
|
|
|
|
before do
|
|
|
|
Discourse.reset_job_exception_stats!
|
|
|
|
end
|
|
|
|
|
|
|
|
after do
|
|
|
|
Discourse.reset_job_exception_stats!
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'collects stats for failing jobs in Discourse.job_exception_stats' do
|
|
|
|
bad = BadJob.new
|
|
|
|
3.times do
|
|
|
|
# During test env handle_job_exception errors out
|
|
|
|
# in production this is suppressed
|
|
|
|
expect { bad.perform({}) }.to raise_error(BadJob::BadJobError)
|
|
|
|
end
|
|
|
|
|
|
|
|
expect(Discourse.job_exception_stats).to eq({ BadJob => 3 })
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
it 'delegates the process call to execute' do
|
2022-11-02 17:47:59 +08:00
|
|
|
::Jobs::Base.any_instance.expects(:execute).with({ 'hello' => 'world' })
|
2019-10-02 12:01:53 +08:00
|
|
|
::Jobs::Base.new.perform('hello' => 'world', 'sync_exec' => true)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'converts to an indifferent access hash' do
|
2019-10-02 12:01:53 +08:00
|
|
|
::Jobs::Base.any_instance.expects(:execute).with(instance_of(HashWithIndifferentAccess))
|
|
|
|
::Jobs::Base.new.perform('hello' => 'world', 'sync_exec' => true)
|
2013-02-26 00:42:20 +08:00
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2020-05-28 19:52:27 +08:00
|
|
|
context "with fake jobs" do
|
|
|
|
let(:common_state) { [] }
|
|
|
|
|
|
|
|
let(:test_job_1) {
|
|
|
|
Class.new(Jobs::Base).tap do |klass|
|
|
|
|
state = common_state
|
|
|
|
klass.define_method(:execute) do |args|
|
|
|
|
state << "job_1_executed"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
let(:test_job_2) {
|
|
|
|
Class.new(Jobs::Base).tap do |klass|
|
|
|
|
state = common_state
|
|
|
|
job_1 = test_job_1
|
|
|
|
klass.define_method(:execute) do |args|
|
|
|
|
state << "job_2_started"
|
|
|
|
Jobs.enqueue(job_1)
|
|
|
|
state << "job_2_finished"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
it "runs jobs synchronously sequentially in tests" do
|
|
|
|
Jobs.run_immediately!
|
|
|
|
Jobs.enqueue(test_job_2)
|
|
|
|
|
|
|
|
expect(common_state).to eq([
|
|
|
|
"job_2_started",
|
|
|
|
"job_2_finished",
|
|
|
|
"job_1_executed"
|
|
|
|
])
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|