Skip to content

Lock traversal ids sync with nowait option

Alex Pooley requested to merge ap-lock-nowait into master

What does this MR do and why?

Don't wait for the database lock if we fail to acquire. This prevents excessive database resource consumption as described in https://gitlab.com/gitlab-com/gl-infra/production-engineering/-/issues/25456#note_1965507452.

MR acceptance checklist

Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Validating

It's very difficult/impossible to replicate this lock in our spec suite due to transactional fixtures. This snippet demonstrates that we can produce this error in normal rails console:

test_model = Group.first

# Start a transaction and acquire a lock on the record
first_thread = Thread.new do
  ActiveRecord::Base.connection_pool.with_connection do
    ActiveRecord::Base.transaction do
      test_model.lock!("FOR NO KEY UPDATE")
      sleep 5 # Keep the lock for a short period to simulate contention
    end
  end
end

# Give the first thread time to acquire the lock
sleep 1

# Attempt to acquire the lock with NOWAIT in another transaction
exception = nil
second_thread = Thread.new do
  ActiveRecord::Base.connection_pool.with_connection do
    begin
      ActiveRecord::Base.transaction do
        test_model.lock!("FOR NO KEY UPDATE NOWAIT")
      end
    rescue ActiveRecord::LockWaitTimeout => e
      if e.message.starts_with? 'PG::LockNotAvailable'
        puts e.inspect
      end
    end
  end
end

first_thread.join
second_thread.join

Closes https://gitlab.com/gitlab-org/gitlab/-/issues/468848

Edited by Alex Pooley

Merge request reports