@@ -9,7 +9,7 @@ class ConcurrencyControlsTest < ActiveSupport::TestCase
9
9
10
10
@result = JobResult . create! ( queue_name : "default" , status : "seq: " )
11
11
12
- default_worker = { queues : "default" , polling_interval : 1 , processes : 3 }
12
+ default_worker = { queues : "default" , polling_interval : 1 , processes : 3 , threads : 2 }
13
13
@pid = run_supervisor_as_fork ( load_configuration_from : { workers : [ default_worker ] } )
14
14
15
15
wait_for_registered_processes ( 4 , timeout : 0.2 . second ) # 3 workers working the default queue + supervisor
@@ -19,19 +19,51 @@ class ConcurrencyControlsTest < ActiveSupport::TestCase
19
19
terminate_process ( @pid ) if process_exists? ( @pid )
20
20
end
21
21
22
- test "run several conflicting jobs and prevent overlapping " do
22
+ test "run several conflicting jobs over the same record sequentially " do
23
23
( "A" .."F" ) . each do |name |
24
- UpdateResultJob . perform_later ( @result , name : name , pause : 0.2 . seconds )
24
+ SequentialUpdateResultJob . perform_later ( @result , name : name , pause : 0.2 . seconds )
25
25
end
26
26
27
27
( "G" .."K" ) . each do |name |
28
- UpdateResultJob . perform_later ( @result , name : name )
28
+ SequentialUpdateResultJob . perform_later ( @result , name : name )
29
29
end
30
30
31
31
wait_for_jobs_to_finish_for ( 4 . seconds )
32
+ assert_no_pending_jobs
33
+
32
34
assert_stored_sequence @result , ( "A" .."K" ) . to_a
33
35
end
34
36
37
+ test "run several jobs over the same record limiting concurrency" do
38
+ incr = 0
39
+ # C is the last one to update the record
40
+ # A: 0 to 0.5
41
+ # B: 0 to 1.0
42
+ # C: 0 to 1.5
43
+ assert_no_difference -> { SolidQueue ::BlockedExecution . count } do
44
+ ( "A" .."C" ) . each do |name |
45
+ ThrottledUpdateResultJob . perform_later ( @result , name : name , pause : ( 0.5 + incr ) . seconds )
46
+ incr += 0.5
47
+ end
48
+ end
49
+
50
+ sleep ( 0.01 ) # To ensure these aren't picked up before ABC
51
+ # D to H: 0.51 to 0.76 (starting after A finishes, and in order, 5 * 0.05 = 0.25)
52
+ # These would finish all before B and C
53
+ assert_difference -> { SolidQueue ::BlockedExecution . count } , +5 do
54
+ ( "D" .."H" ) . each do |name |
55
+ ThrottledUpdateResultJob . perform_later ( @result , name : name , pause : 0.05 . seconds )
56
+ end
57
+ end
58
+
59
+ wait_for_jobs_to_finish_for ( 3 . seconds )
60
+ assert_no_pending_jobs
61
+
62
+ # C would have started in the beginning, seeing the status empty, and would finish after
63
+ # all other jobs, so it'll do the last update with only itself
64
+ assert_stored_sequence ( @result , [ "C" ] )
65
+ end
66
+
35
67
private
36
68
def assert_stored_sequence ( result , sequence )
37
69
expected = "seq: " + sequence . map { |name | "s#{ name } c#{ name } " } . join
0 commit comments