Packages

Extends Redix with Redis cluster support

Current section

Files

Jump to
redis_cluster lib redis_cluster.ex
Raw

lib/redis_cluster.ex

defmodule RedisCluster do
@moduledoc """
This module is a thin wrapper around the `RedisCluster.Cluster` module.
First, you will need a module to `use` this module.
```elixir
defmodule MyApp.Redis do
use RedisCluster, otp_app: :my_app
end
```
Then you need to include the relevant config in your `config.exs` (or `runtime.exs`):
```elixir
config :my_app, MyApp.Redis,
host: "localhost",
port: 6379,
pool_size: 10
```
Ideally, your `host` should a configuration endpoint for ElastiCache (or equivalent).
This endpoint picks a random node in the cluster to connect to for discovering the cluster.
Your module will have basic Redis functions like `get`, `set`, and `delete`.
You can also run arbitrary Redis commands with `command` and `pipeline`.
You may also want to include other convenience functions in your module:
```elixir
defmodule MyApp.Redis do
use RedisCluster, otp_app: :my_app
def hget(key, field) do
# Implementation here...
end
def hgetall(key) do
# Implementation here...
end
def hset(key, field, value) do
# Implementation here...
end
end
```
Don't forget to start the Redis cluster in your application supervision tree, probably in `lib/my_app/application.ex`:
```elixir
def start(_type, _args) do
children = [
MyApp.Redis,
# Other children...
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
```
Alternatively, you can use the `RedisCluster.Cluster` module directly.
```elixir
config = %RedisCluster.Configuration{
host: "localhost",
port: 6379,
pool_size: 3,
name: Test.Redis,
registry: Test.Redis.Registry__,
pool: Test.Redis.Pool__,
cluster: Test.Redis.Cluster__,
shard_discovery: Test.Redis.ShardDiscovery__
}
{:ok, pid} = RedisCluster.Cluster.start_link(config)
RedisCluster.Cluster.set(config, "answer", 42)
RedisCluster.Cluster.get(config, "answer")
```
This can be useful for testing, Livebook demos, or dynamically connecting to Redis clusters.
"""
defmacro __using__(macro_opts) do
quote bind_quoted: [macro_opts: macro_opts] do
def start_link(_) do
RedisCluster.Cluster.start_link(config())
end
def child_spec(opts \\ []) do
RedisCluster.Cluster.child_spec(config(), opts)
end
def config() do
RedisCluster.Configuration.from_app_env(unquote(macro_opts), __MODULE__)
end
def get(key, opts \\ []) do
RedisCluster.Cluster.get(config(), key, opts)
end
def get_many(keys, opts \\ []) do
RedisCluster.Cluster.get_many(config(), keys, opts)
end
def get_many_async(keys, opts \\ []) do
RedisCluster.Cluster.get_many_async(config(), keys, opts)
end
def set(key, value, opts \\ []) do
RedisCluster.Cluster.set(config(), key, value, opts)
end
def set_many(entries, opts \\ []) do
RedisCluster.Cluster.set_many(config(), entries, opts)
end
def set_many_async(entries, opts \\ []) do
RedisCluster.Cluster.set_many_async(config(), entries, opts)
end
def delete(key, opts \\ []) do
RedisCluster.Cluster.delete(config(), key, opts)
end
def delete_many(keys, opts \\ []) do
RedisCluster.Cluster.delete_many(config(), keys, opts)
end
def delete_many_async(keys, opts \\ []) do
RedisCluster.Cluster.delete_many_async(config(), keys, opts)
end
@deprecated "Use `command/3` instead."
def command(command, opts) do
key = Keyword.fetch!(opts, :key)
command(command, key, opts)
end
def command(command, key, opts) do
RedisCluster.Cluster.command(config(), command, key, opts)
end
@deprecated "Use `command!/3` instead."
def command!(command, opts) do
command
|> command(opts)
|> bang!()
end
def command!(command, key, opts) do
command
|> command(key, opts)
|> bang!()
end
@deprecated "Use `pipeline/3` instead."
def pipeline(commands, opts) do
key = Keyword.fetch!(opts, :key)
pipeline(commands, key, opts)
end
def pipeline(commands, key, opts) do
RedisCluster.Cluster.pipeline(config(), commands, key, opts)
end
@deprecated "Use `pipeline!/3` instead."
def pipeline!(commands, opts) do
commands
|> pipeline(opts)
|> bang!()
end
def pipeline!(commands, key, opts) do
commands
|> pipeline(key, opts)
|> bang!()
end
def slot_table() do
RedisCluster.HashSlots.all_slots_as_table(config())
end
defp bang!(result) do
case result do
{:ok, response} -> response
{:error, error} -> raise error
other -> other
end
end
end
end
end