Lock traversal ids sync with nowait option
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
Edited by Alex Pooley