@@ -34,8 +34,10 @@ def submission_result(data)
3434 update_hash [ :total_time ] = tasks . map { |i | i . time } . sum . round ( 0 )
3535 update_hash [ :total_memory ] = tasks . map { |i | i . rss } . max || 0
3636 end
37- submission . with_lock do
38- submission . update ( **update_hash )
37+ retry_lock do
38+ submission . with_lock do
39+ submission . update ( **update_hash )
40+ end
3941 end
4042 ActionCable . server . broadcast ( "submission_#{ submission . id } _overall" , update_hash . merge ( { id : submission . id } ) )
4143 end
@@ -53,22 +55,25 @@ def fetch_submission(data)
5355 is_old = false
5456 for i in 1 ..n_retry
5557 is_old = false
56- flag = false
5758 submission = Submission . where ( result : "queued" ) . order ( Arel . sql ( 'contest_id IS NOT NULL ASC' ) , id : :asc ) . first
5859 if not submission and Submission . where ( contest_id : nil , new_rejudged : false , result : [ "received" , "Validating" ] ) . count < 10
5960 submission = Submission . where ( contest_id : nil , new_rejudged : false ) . where . not ( result : [ "received" , "Validating" ] ) . order ( result : :asc , id : :desc ) . first
6061 is_old = true
6162 end
63+ flag = false
6264 if submission
63- submission . with_lock do
64- if submission . result == "received"
65- if i != n_retry
66- flag = true
67- next # breaks with_lock
65+ retry_lock ( 3 ) do
66+ submission . with_lock do
67+ if submission . result == "received"
68+ if i != n_retry
69+ flag = true
70+ next # breaks with_lock
71+ end
72+ return
6873 end
69- return
74+ submission . update ( result : "received" )
7075 end
71- submission . update ( result : "received" )
76+ next if flag
7277 end
7378 next if flag
7479 else
@@ -152,11 +157,28 @@ def update_task_results(data, submission)
152157 score = td_set_scores . sum { |x | x [ :score ] }
153158 max_score = BigDecimal ( '1e+12' ) - 1
154159 score = score . clamp ( -max_score , max_score ) . round ( 6 )
155- submission . with_lock do
156- return if submission . new_rejudged and not [ 'Validating' , 'received' ] . include? ( submission . result )
157- submission . update ( :score => score )
160+ retry_lock do
161+ submission . with_lock do
162+ return if submission . new_rejudged and not [ 'Validating' , 'received' ] . include? ( submission . result )
163+ submission . update ( :score => score )
164+ end
158165 end
159166 ActionCable . server . broadcast ( "submission_#{ submission . id } " , { td_set_scores : td_set_scores , tasks : results } )
160167 ActionCable . server . broadcast ( "submission_#{ submission . id } _overall" , { score : score , result : submission . result , id : submission . id } )
161168 end
169+
170+ def retry_lock ( retry_times = 4 , interval = 0.3 )
171+ begin
172+ raise ActiveRecord ::Deadlocked if retry_times == 4
173+ yield
174+ rescue ActiveRecord ::Deadlocked => e
175+ retry_times -= 1
176+ if retry_times > 0
177+ sleep interval
178+ retry
179+ else
180+ raise e
181+ end
182+ end
183+ end
162184end
0 commit comments