gear 1 gear 2 gear 3 gear 4
DE | EN
clock-work-coder

🔒 How I Debugged and Released a Stuck Rails Migration Lock in MySQL

Recently, I ran into a frustrating issue where Rails migrations wouldn’t run because the advisory lock used to prevent concurrent migrations was stuck. Here's how I investigated and forcefully released it using the Rails console.


🧠 The Problem

When Rails runs migrations, it uses MySQL advisory locks under the hood to prevent multiple migration processes from running at the same time. This is implemented using GET_LOCK(lock_id, timeout) and RELEASE_LOCK(lock_id).

However, in my case, trying to acquire or release the lock failed:

ActiveRecord::Base.connection.get_advisory_lock(lock_id)
# => false

ActiveRecord::Base.connection.release_advisory_lock(lock_id)
# => false

This meant:

  • I didn't currently hold the lock.
  • Someone else (or some orphaned session) did.
  • Rails migrations were blocked indefinitely.

🔍 Investigating the Lock

1. Find the advisory lock ID Rails uses

Rails 6.1 uses this pattern to generate the migration lock ID for MySQL:

lock_id = ActiveRecord::Migrator::MIGRATOR_SALT * 
  Zlib.crc32(ActiveRecord::Base.connection.current_database)

This ensures a unique lock ID per database. The salt or way this ID is generated might change so you have to check the source for your specific version.

2. Check who holds the lock

ActiveRecord::Base.connection.select_value("SELECT IS_USED_LOCK(#{lock_id})")
# => 1562  (example thread ID)

This tells you the MySQL thread ID of the session currently holding the lock.


🛠 Releasing the Stuck Lock

To forcefully release the lock, I killed the owning session:

ActiveRecord::Base.connection.execute("KILL 1562")

Then I confirmed the lock was gone:

ActiveRecord::Base.connection.select_value("SELECT IS_USED_LOCK(#{lock_id})")
# => nil

Now, I could acquire and release the lock normally:

ActiveRecord::Base.connection.get_advisory_lock(lock_id)
# => true

ActiveRecord::Base.connection.release_advisory_lock(lock_id)
# => true

✅ Full IRB Session

lock_id = ActiveRecord::Migrator::MIGRATOR_SALT * 
  Zlib.crc32(ActiveRecord::Base.connection.current_database)

ActiveRecord::Base.connection.get_advisory_lock(lock_id)
# => false

ActiveRecord::Base.connection.release_advisory_lock(lock_id)
# => false

ActiveRecord::Base.connection.select_value("SELECT IS_USED_LOCK(#{lock_id})")
# => 1562

ActiveRecord::Base.connection.execute("KILL 1562")
# => nil

ActiveRecord::Base.connection.select_value("SELECT IS_USED_LOCK(#{lock_id})")
# => nil

ActiveRecord::Base.connection.get_advisory_lock(lock_id)
# => true

ActiveRecord::Base.connection.release_advisory_lock(lock_id)
# => true

🧠 Takeaways

  • Rails uses MySQL advisory locks for migration locking.
  • These are connection-scoped and invisible unless you ask.
  • Use IS_USED_LOCK() and KILL to troubleshoot stuck locks.
  • Always check carefully before killing DB sessions.

How to build your own serverless URL shortener service

At Homeday Medium my college Mohamed Barakat gave an introduction to the URL-Shorterner Service which we realized within our Product Engineering Week (PEW).

I want to take the opportunity to write more in detailed regarding implementation details in our next PEW (March 2021)

24pullrequests retrospective 2015

As described in my blog post developer-advent-calender-2015 I wanted to give something back to the Open-Source-Community as a kind of a christmas present. So here there is a brief overview of the results. Long story short; No, I haven't reached my final goal of placing 24 PRs or above. But thats something I can aim at in 2016 though ^^

the projects

(I'll skip an introduction of each and every project, those can be found in the respective projects README.md)

results

12 PRs thereof 11 already merged (see here). Anyhow my intention for 2016 is to contribute more continuously rather then waiting until it is december.

The slightly different advent calender

Instead of opening calendar doors each day once again one can give little presents back to the open source community on 24pullrequests.com. You are encouraged to contribute on daily basis to one or more projects by sending pull requests (PR), the way of giving something back to the OS-World.

Why?

...since many developers rely and work on daily basis with frameworks and tools which are open, free and enhanceable(!). So it should rather be a duty and christmas is the perfect time to do so. Besides digging into new, unknown projects gives you a lot of new insights and you'll learn quite a lot from how others are solving problems.

Strategy

I can conclude that my choosen strategy for last year was rather unsuccessful. I tried to contribute to a different project each day and ended up with round about 6 PRs. This is due to the high amount of work you have to actually put into understanding and get the project and its tests up and running. (This took like 2-3 hours for each of the projects bringing me to the state there I could actually start to work on my contribution. That was far to much I was able to spend after work each day ;)) So this year I will rather fokus on a smaller group of chosen projects, however trying to place several PRs for each project.

Happy Coding!

My progress can be followed here. Let's see if I am able to manage the challenge this year.