{"id":21500642,"url":"https://github.com/podium/redis_mutex","last_synced_at":"2025-08-20T18:14:26.143Z","repository":{"id":57542332,"uuid":"86660352","full_name":"podium/redis_mutex","owner":"podium","description":"Elixir redis mutex implementation","archived":false,"fork":false,"pushed_at":"2025-08-19T00:14:29.000Z","size":129,"stargazers_count":13,"open_issues_count":0,"forks_count":6,"subscribers_count":46,"default_branch":"master","last_synced_at":"2025-08-19T01:20:44.578Z","etag":null,"topics":["elixir","elixir-lang","redis","redis-mutex"],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/redis_mutex","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/podium.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-03-30T04:53:21.000Z","updated_at":"2025-08-19T00:14:32.000Z","dependencies_parsed_at":"2023-11-09T00:26:21.128Z","dependency_job_id":"19c0af90-3e6d-45dd-b9c3-45b272bd5fde","html_url":"https://github.com/podium/redis_mutex","commit_stats":{"total_commits":32,"total_committers":8,"mean_commits":4.0,"dds":0.59375,"last_synced_commit":"c51a3bf0db0df4368c2fbb01bddd90c765625489"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/podium/redis_mutex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/podium%2Fredis_mutex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/podium%2Fredis_mutex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/podium%2Fredis_mutex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/podium%2Fredis_mutex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/podium","download_url":"https://codeload.github.com/podium/redis_mutex/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/podium%2Fredis_mutex/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271362439,"owners_count":24746498,"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","status":"online","status_checked_at":"2025-08-20T02:00:09.606Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["elixir","elixir-lang","redis","redis-mutex"],"created_at":"2024-11-23T17:42:58.300Z","updated_at":"2025-08-20T18:14:26.095Z","avatar_url":"https://github.com/podium.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RedisMutex\n\n[![Build Status](https://github.com/podium/redis_mutex/actions/workflows/ci.yml/badge.svg)](https://github.com/podium/redis_mutex/actions/workflows/ci.yml) [![Hex.pm](https://img.shields.io/hexpm/v/redis_mutex.svg)](https://hex.pm/packages/redis_mutex) [![Documentation](https://img.shields.io/badge/documentation-gray)](https://hexdocs.pm/redis_mutex)\n[![Total Download](https://img.shields.io/hexpm/dt/redis_mutex.svg)](https://hex.pm/packages/redis_mutex)\n[![License](https://img.shields.io/hexpm/l/redis_mutex.svg)](https://github.com/podium/redis_mutex/blob/master/LICENSE.md)\n\nRedisMutex is a library for creating a Redis lock for a single Redis instance.\n\n## Installation\n\nThe package can be installed by adding `redis_mutex`\nto your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:redis_mutex, \"~\u003e 1.0\"}\n  ]\nend\n```\n\n## Upgrading from version 0.X to version 1.X\n\nVersion 1.0.0 of `RedisMutex` changes how `RedisMutex` is started and how `with_lock` is used. Key changes include:\n\n1. `RedisMutex` no longer runs as its own application.\n   1. If you need or want to set up a Redix connection specifically for `RedisMutex`, it must be added to your application's\n      supervision tree.\n   2. If you want to re-use an existing Redis connection via Redix, it does not need adding to your application's\n      supervision tree.\n2. Using `RedisMutex`'s `with_lock` is no longer done via `use RedisMutex`. Instead, your application must call\n   the function `RedisMutex.with_lock/3`.\n3. The code you want to execute in `RedisMutex.with_lock/3` is passed in a zero-arity function instead of in a `do`\n   block.\n4. Timeout and expiry options for `RedisMutex.with_lock/3` are optionally provided in a keyword list as the last\n   argument to `RedisMutex.with_lock/3`.\n5. Callbacks are defined for `RedisMutex`'s functions to allow for doubles to be used in testing.\n\nIn order to upgrade to version 1.X, you will need to:\n1. Add `RedisMutex` to your application's supervision tree unless you are using an existing Redis connection via Redix.\n2. Remove use of `use RedisMutex` in favor of `RedisMutex.with_lock/3`.\n3. Replace the `do` block with a zero-arity function in your calls to `RedisMutex.with_lock/3`.\n4. Move any timeout or expiry arguments into a keyword list as the final argument to `RedisMutex.with_lock/3`.\n5. If you are not running Redis when you run your unit tests, update your test suite to use a double\n   that handles `RedisMutex`'s updated functions.\n\n### What is involved in updating the use of `with_lock`?\n\nHere's a quick example of the changes that need to be made to how you use `with_lock`.\n\n#### Using `with_lock` in version 0.X\n\n```elixir\ndefmodule PossumLodge do\n  use RedisMutex\n\n  def get_oauth do\n    with_lock(\"my_key\") do\n      \"Quando omni flunkus moritati\"\n    end\n  end\nend\n```\n\n#### Using `with_lock` in version 1.X\n\n```elixir\ndefmodule PossumLodge do\n\n  def get_oauth do\n    RedisMutex.with_lock(\"my_key\", fn -\u003e\n      \"Quando omni flunkus moritati\"\n    end)\n  end\nend\n```\n\nPlease see the [Usage](#usage) section for more details and examples.\n\n## Usage\n\n`RedisMutex` offers the user flexibility in how it is used.\n\nIf you already have a named connection to Redis and want to re-use that, using `RedisMutex` is dead simple.\n\nIf you need to start a named connection to Redis for a mutex, you can do so via `RedisMutex`.`RedisMutex` offers\na default connection name when starting your connection to Redis. This is the simplest way to use `RedisMutex`,\nand it is the default.\n\nIf you want to customize the name used for that connection, you can specify a name to use for the connection.\n\n### Using an existing named connection to Redis\n\nIn order to use an existing connection, you can simply pass the name of that connection as an option to\n`RedisMutex.with_lock/3`\n\n```elixir\ndefmodule PossumLodge do\n  @redis_connection_opts [name: :my_existing_redis_connection]\n\n  def get_oauth do\n    RedisMutex.with_lock(\n      \"my_key\",\n      fn -\u003e \"Quando omni flunkus moritati\" end,\n      @redis_connection_opts\n    )\n  end\nend\n```\n\n### Starting a new connection to Redis\n\nIf you don't have an existing connection that you want to re-use, and you want to start a connection for `RedisMutex`,\nyou need to set options in your configuration and add `RedisMutex` to your application's supervision tree.\n\nIf you have a named connection to Redis that you want to re-use, you do not need to add `RedisMutex`\nto your application's supervision tree.\n\n#### Using `RedisMutex`'s defaults\n\nBy default, `RedisMutex` will use `:redis_mutex_connection` as the name for setting up a connection to Redis.\n\n#### Adding `RedisMutex` to your application's supervision tree with `RedisMutex`'s defaults\n\nSet the `options` in your for `RedisMutex` in your supervision tree. The options can be a `redis_url` or a set of \noptions for Redis. See `RedisMutex.start_options` for details.\n\nBy default, `RedisMutex` will use `:redis_mutex_connection` as the name for setting up a connection to Redis.\n\n##### Example with the default name and a `redis_url`\n\n```elixir\n  @impl Application\n  def start(_type, _args) do\n    children = other_children() ++ [{RedisMutex, redis_url: System.get_env(\"REDIS_URL\")}]\n    Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)\n  end\n```\n##### Example with the default name and other connection options\n\n```elixir\n  @impl Application\n  def start(_type, _args) do\n    children = other_children() ++ [{RedisMutex, host: System.get_env(\"REDIS_URL\"), port: System.get_env(\"REDIS_PORT\")}]\n    Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)\n  end\n```\n\n#### Using a custom connection name\n\nIf you want to start a connection with a name other than `RedisMutex`, you should specify the name you\nwant to use when adding `RedisMutex` to your application's supervision tree. You will also need to provide this \nname as an option to the lock function when using `RedisMutex`.\n\n#### Adding `RedisMutex` to your application's supervision tree with a custom connection name\n\nIn order to specify the connection name, include it as an option when adding `RedisMutex` to your\napplication's supervision tree.\n\n##### Example with a name specified and a `redis_url`\n\n```elixir\n  @impl Application\n  def start(_type, _args) do\n    children = other_children() ++ [\n      {RedisMutex, \n        name: MyApp.Mutex, \n        redis_url: System.get_env(\"REDIS_URL\", \"redis://localhost:6379\")\n      }\n    ]\n    Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)\n  end\n```\n##### Example with a name specified and other connection options\n\n```elixir\n  @impl Application\n  def start(_type, _args) do\n    children = other_children() ++ [\n      {RedisMutex, \n        name: MyApp.RedisMutex,\n        host: System.get_env(\"REDIS_HOST\", \"localhost\"), \n        port: System.get_env(\"REDIS_PORT\", 6379)\n      }\n    ]\n    Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)\n  end\n```\n\n### Wrapping `RedisMutex`\n\nIf you are using a custom connection name and want to simplify the use of `RedisMutex`, you can\nwrite a wrapper module for `RedisMutex` and add that module to your application's supervision tree.\n\n#### Sample wrapper module\n```elixir\ndefmodule MyApp.Mutex do\n\n  @redis_mutex Application.compile_env(:my_app, :redis_mutex, RedisMutex)\n  \n  def child_spec(opts) do\n    child_spec_opts = Keyword.merge(opts, name: MyApp.Mutex)\n    @redis_mutex.child_spec(child_spec_opts)\n  end\n  \n  def start_link(start_options) do\n    @redis_mutex.start_link(start_options)\n  end\n  \n  def with_lock(key, opts, fun) do\n    lock_options = Keyword.merge(opts, name: MyApp.Mutex)\n    @redis_mutex.with_lock(key, fun, lock_options)\n  end\nend\n```\n\n#### Adding the wrapper module to the supervision tree \n```elixir\n  @impl Application\n  def start(_type, _args) do\n    children = other_children() ++ [\n      {MyApp.Mutex,\n      redis_url: System.get_env(\"REDIS_URL\")\n      }\n    ]\n    Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)\n  end\n```\n\n### Using `RedisMutex`\n\nCall `RedisMutex`'s `with_lock/3` function to lock critical parts of your code. `with_lock/3` must be\nprovided with a `key` argument and a zero-arity function argument to call. This function will be called\nif and when the lock is acquired.\n\n```elixir\ndefmodule PossumLodge do\n\n  @redis_mutex Application.compile_env(:my_app, :redis_mutex, RedisMutex)\n  \n  def get_oauth do\n    @redis_mutex.with_lock(\"my_key\", fn -\u003e\n      \"Quando omni flunkus moritati\"\n    end)\n  end\nend\n```\n\n`with_lock/3` also allows setting options, including a name for the connection, a timeout and an\nexpiry, both in milliseconds. If you have specified a custom connection name or are re-using an\nexisting named connection to redis, the name of that connection must be included in the options\nwhen calling `with_lock/3`.\n\n```elixir\ndefmodule PossumLodge do\n\n  @redis_mutex Application.compile_env(:my_app, :redis_mutex, RedisMutex)\n  @mutex_options [name: MyApp.Mutex, timeout: 500, expiry: 1_000]\n  \n  def get_oauth do\n    @redis_mutex.with_lock(\n      \"my_key\", \n      fn -\u003e \"Quando omni flunkus moritati\" end,\n      @mutex_options\n      )\n  end\nend\n```\n\n\n## Testing your application with `RedisMutex`\n\n### Testing your application with Redis running\n\nIf you are running Redis when you are running your test suite, simply having the `redis_mutex` config set and \nrunning the default command works:\n\n```\nmix test\n```\n\n### Testing your application without an instance of Redis running\n\nIf you want to test your application without an instance of Redis running, you will need to define a double for\n`RedisMutex`. `RedisMutex` defines callbacks for `child_spec/1`, `start_link/1`, `with_lock/2` and `with_lock/3`.\n\n#### Define a mock for `RedisMutex`\n\nIf you are using `Mox`, you can define the mock along with your other mocks.\n\n```\nMox.defmock(RedisMutexMock, for: RedisMutex)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpodium%2Fredis_mutex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpodium%2Fredis_mutex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpodium%2Fredis_mutex/lists"}