{"id":13880208,"url":"https://github.com/ClosureTree/with_advisory_lock","last_synced_at":"2025-07-16T16:31:19.155Z","repository":{"id":6473401,"uuid":"7713384","full_name":"ClosureTree/with_advisory_lock","owner":"ClosureTree","description":"Advisory locking for ActiveRecord","archived":false,"fork":false,"pushed_at":"2025-07-05T01:32:30.000Z","size":300,"stargazers_count":657,"open_issues_count":8,"forks_count":70,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-07-13T11:53:34.706Z","etag":null,"topics":["activerecord","advisory-locks","mutexes","mysql","postgres","postgresql","ruby","transaction"],"latest_commit_sha":null,"homepage":"http://closuretree.github.io/with_advisory_lock/","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ClosureTree.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2013-01-20T06:16:07.000Z","updated_at":"2025-07-05T01:32:25.000Z","dependencies_parsed_at":"2023-10-15T17:42:00.221Z","dependency_job_id":"228eab80-2d66-40e6-a1dd-d32ca5b7c9cb","html_url":"https://github.com/ClosureTree/with_advisory_lock","commit_stats":{"total_commits":167,"total_committers":21,"mean_commits":"7.9523809523809526","dds":"0.40718562874251496","last_synced_commit":"00f1cfe81c231aabf1f8c7c3c2b7be844df031c6"},"previous_names":["mceachen/with_advisory_lock"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/ClosureTree/with_advisory_lock","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ClosureTree%2Fwith_advisory_lock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ClosureTree%2Fwith_advisory_lock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ClosureTree%2Fwith_advisory_lock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ClosureTree%2Fwith_advisory_lock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ClosureTree","download_url":"https://codeload.github.com/ClosureTree/with_advisory_lock/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ClosureTree%2Fwith_advisory_lock/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265524630,"owners_count":23782016,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","advisory-locks","mutexes","mysql","postgres","postgresql","ruby","transaction"],"created_at":"2024-08-06T08:02:52.052Z","updated_at":"2025-07-16T16:31:19.147Z","avatar_url":"https://github.com/ClosureTree.png","language":"Ruby","readme":"# with_advisory_lock\n\nAdds advisory locking (mutexes) to ActiveRecord 7.2+, with ruby 3.3+, jruby or truffleruby, when used with\n[MySQL](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_get-lock)\nor\n[PostgreSQL](https://www.postgresql.org/docs/current/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS).\n\n**Note:** SQLite support has been removed. For single-node SQLite deployments,\nconsider using a Ruby mutex instead. Support for MySQL 5.7 has also been\ndropped; please use MySQL 8 or PostgreSQL.\n\n[![Gem Version](https://badge.fury.io/rb/with_advisory_lock.svg)](https://badge.fury.io/rb/with_advisory_lock)\n[![CI](https://github.com/ClosureTree/with_advisory_lock/actions/workflows/ci.yml/badge.svg)](https://github.com/ClosureTree/with_advisory_lock/actions/workflows/ci.yml)\n\n## What's an \"Advisory Lock\"?\n\nAn advisory lock is a [mutex](https://en.wikipedia.org/wiki/Mutual_exclusion)\nused to ensure no two processes run some process at the same time. When the\nadvisory lock is powered by your database server,\nyour mutex spans hosts.\n\n## Usage\n\nThis gem automatically includes the `WithAdvisoryLock` module in all of your\nActiveRecord models. Here's an example of how to use it where `User` is an\nActiveRecord model, and `lock_name` is some string:\n\n```ruby\nUser.with_advisory_lock(lock_name) do\n  do_something_that_needs_locking\nend\n```\n\n### What happens\n\n1. The thread will wait indefinitely until the lock is acquired.\n2. While inside the block, you will exclusively own the advisory lock.\n3. The lock will be released after your block ends, even if an exception is raised in the block.\n\n### Lock wait timeouts\n\n`with_advisory_lock` takes an options hash as the second parameter. The\n`timeout_seconds` option defaults to `nil`, which means wait indefinitely for\nthe lock.\n\nA value of zero will try the lock only once. If the lock is acquired, the block\nwill be yielded to. If the lock is currently being held, the block will not be\ncalled.\n\n\u003e **Note**\n\u003e \n\u003e If a non-nil value is provided for `timeout_seconds`, the block will\n*not* be invoked if the lock cannot be acquired within that time-frame. In this case, `with_advisory_lock` will return `false`, while `with_advisory_lock!` will raise a `WithAdvisoryLock::FailedToAcquireLock` error.\n\nFor backwards compatability, the timeout value can be specified directly as the\nsecond parameter.\n\n### Shared locks\n\nThe `shared` option defaults to `false` which means an exclusive lock will be\nobtained. Setting `shared` to `true` will allow locks to be obtained by multiple\nactors as long as they are all shared locks.\n\nNote: MySQL does not support shared locks.\n\n### Transaction-level locks\n\nPostgreSQL supports transaction-level locks which remain held until the\ntransaction completes. You can enable this by setting the `transaction` option\nto `true`.\n\nNote: transaction-level locks will not be reflected by `.current_advisory_lock`\nwhen the block has returned.\n\n### Return values\n\nThe return value of `with_advisory_lock_result` is a `WithAdvisoryLock::Result`\ninstance, which has a `lock_was_acquired?` method and a `result` accessor\nmethod, which is the returned value of the given block. If your block may\nvalidly return false, you should use this method.\n\nThe return value of `with_advisory_lock` will be the result of the yielded\nblock, if the lock was able to be acquired and the block yielded, or `false`, if\nyou provided a timeout_seconds value and the lock was not able to be acquired in\ntime.\n\n`with_advisory_lock!` is similar to `with_advisory_lock`, but raises a `WithAdvisoryLock::FailedToAcquireLock` error if the lock was not able to be acquired in time. \n\n### Testing for the current lock status\n\nIf you needed to check if the advisory lock is currently being held, you can\ncall `Tag.advisory_lock_exists?(\"foo\")`, but realize the lock can be acquired\nbetween the time you test for the lock, and the time you try to acquire the\nlock.\n\nIf you want to see if the current Thread is holding a lock, you can call\n`Tag.current_advisory_lock` which will return the name of the current lock. If\nno lock is currently held, `.current_advisory_lock` returns `nil`.\n\n### ActiveRecord Query Cache\n\nYou can optionally pass `disable_query_cache: true` to the options hash of\n`with_advisory_lock` in order to disable ActiveRecord's query cache. This can\nprevent problems when you query the database from within the lock and it returns\nstale results. More info on why this can be a problem can be\n[found here](https://github.com/ClosureTree/with_advisory_lock/issues/52)\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'with_advisory_lock'\n```\n\nAnd then execute:\n\n    $ bundle\n\n## Lock Types\n\nFirst off, know that there are **lots** of different kinds of locks available to\nyou. **Pick the finest-grain lock that ensures correctness.** If you choose a\nlock that is too coarse, you are unnecessarily blocking other processes.\n\n### Advisory locks\n\nThese are named mutexes that are inherently \"application level\"—it is up to the\napplication to acquire, run a critical code section, and release the advisory\nlock.\n\n### Row-level locks\n\nWhether [optimistic](http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html)\nor [pessimistic](http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html),\nrow-level locks prevent concurrent modification to a given model.\n\n**If you're building a\n[CRUD](http://en.wikipedia.org/wiki/Create,_read,_update_and_delete)\napplication, this will be 2.4, 2.5 and your most commonly used lock.**\n\n### Table-level locks\n\nProvided through something like the\n[monogamy](https://github.com/ClosureTree/monogamy) gem, these prevent\nconcurrent access to **any instance of a model**. Their coarseness means they\naren't going to be commonly applicable, and they can be a source of\n[deadlocks](http://en.wikipedia.org/wiki/Deadlock).\n\n## FAQ\n\n### Transactions and Advisory Locks\n\nAdvisory locks with MySQL and PostgreSQL ignore database transaction boundaries.\n\nYou will want to wrap your block within a transaction to ensure consistency.\n\n### Is clustered MySQL supported?\n\n[No.](https://github.com/ClosureTree/with_advisory_lock/issues/16)\n\n","funding_links":[],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FClosureTree%2Fwith_advisory_lock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FClosureTree%2Fwith_advisory_lock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FClosureTree%2Fwith_advisory_lock/lists"}