Skip to content

Commit 9d57925

Browse files
committed
Dispatch blocked jobs after job perform finishes outside that transaction
Otherwise, if a job finishes just fine or fails, and something goes wrong when dispatching blocked jobs, we'll fail to mark the job as finished or failed just because we couldn't dispatch blocked jobs, but not because anything went wrong with the job itself. Also: test sequential jobs when some of them fail. We must continue processing jobs normally.
1 parent 5f5578d commit 9d57925

File tree

5 files changed

+26
-10
lines changed

5 files changed

+26
-10
lines changed

app/models/solid_queue/claimed_execution.rb

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ def perform
3333
else
3434
failed_with(result.error)
3535
end
36+
ensure
37+
job.dispatch_blocked_jobs
3638
end
3739

3840
def release

app/models/solid_queue/job/concurrency_controls.rb

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ module ConcurrencyControls
77
has_one :blocked_execution, dependent: :destroy
88
end
99

10+
def dispatch_blocked_jobs
11+
if release_concurrency_lock
12+
release_next_blocked_job
13+
end
14+
end
15+
1016
private
1117
def acquire_concurrency_lock
1218
return true unless concurrency_limited?

app/models/solid_queue/job/executable.rb

-8
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ def prepare_for_execution
2828

2929
def finished
3030
touch(:finished_at)
31-
dispatch_blocked_jobs
3231
end
3332

3433
def finished?
@@ -37,7 +36,6 @@ def finished?
3736

3837
def failed_with(exception)
3938
FailedExecution.create_or_find_by!(job_id: id, exception: exception)
40-
dispatch_blocked_jobs
4139
end
4240

4341
def discard
@@ -60,12 +58,6 @@ def dispatch
6058
end
6159
end
6260

63-
def dispatch_blocked_jobs
64-
if release_concurrency_lock
65-
release_next_blocked_job
66-
end
67-
end
68-
6961
def schedule
7062
ScheduledExecution.create_or_find_by!(job_id: id)
7163
end

test/dummy/app/jobs/update_result_job.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
class UpdateResultJob < ApplicationJob
22
include ActiveJob::ConcurrencyControls
33

4-
def perform(job_result, name:, pause: nil)
4+
def perform(job_result, name:, pause: nil, exception: nil)
55
job_result.status += "s#{name}"
6-
job_result.save!
76

87
sleep(pause) if pause
8+
raise exception.new if exception
99

1010
job_result.status += "c#{name}"
1111
job_result.save!

test/integration/concurrency_controls_test.rb

+16
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,22 @@ class ConcurrencyControlsTest < ActiveSupport::TestCase
6464
assert_stored_sequence(@result, [ "C" ])
6565
end
6666

67+
test "run several jobs over the same record sequentially, with some of them failing" do
68+
("A".."F").each_with_index do |name, i|
69+
# A, C, E will fail, for i= 0, 2, 4
70+
SequentialUpdateResultJob.perform_later(@result, name: name, pause: 0.2.seconds, exception: (RuntimeError if i.even?))
71+
end
72+
73+
("G".."K").each do |name|
74+
SequentialUpdateResultJob.perform_later(@result, name: name)
75+
end
76+
77+
wait_for_jobs_to_finish_for(4.seconds)
78+
assert_equal 3, SolidQueue::FailedExecution.count
79+
80+
assert_stored_sequence @result, [ "B", "D", "F" ] + ("G".."K").to_a
81+
end
82+
6783
private
6884
def assert_stored_sequence(result, sequence)
6985
expected = "seq: " + sequence.map { |name| "s#{name}c#{name}"}.join

0 commit comments

Comments
 (0)