Skip to content

Commit

Permalink
Fix #upsert_status race condition.
Browse files Browse the repository at this point in the history
Rescue ActiveRecord::RecordNotUnique and then retry.
  • Loading branch information
ba1ash committed Feb 28, 2024
1 parent f2ffac9 commit f296c54
Showing 1 changed file with 10 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@
#++
module JobStatus
module ApplicationJobWithStatus
# Delayed jobs can have a status:
# Delayed::Job::Status
# Backgroun jobs can have a status JobStatus::Status
# which is related to the job via a reference which is an AR model instance.
def status_reference
nil
Expand Down Expand Up @@ -61,8 +60,6 @@ def job_status
##
# Update the status code for a given job
def upsert_status(status:, **args)
# Can't use upsert, as we only want to insert the user_id once
# and not update it repeatedly
resource = ::JobStatus::Status.find_or_initialize_by(job_id:)

if resource.new_record?
Expand All @@ -77,7 +74,16 @@ def upsert_status(status:, **args)
resource.attributes = build_status_attributes(args.merge(status:))
end

# There is a possible race condition because of unique delayed_job_statuses.job_id
# Can't use upsert easily, because before updating we need to know user_id
# to set proper locale. Probably, it is possible to get it from
# a job's payload, then it would be possible to correctly prepare attributes before using upsert.
# Therefore, it is up to possible optimization in future. Now the race condition is handled with
# handling ActiveRecord::RecordNotUnique and trying again.
resource.save!
rescue ActiveRecord::RecordNotUnique
OpenProject.logger.info("Retrying ApplicationJobWithStatus#upsert_status.")
retry
end

protected
Expand Down

0 comments on commit f296c54

Please sign in to comment.