Packages

Simple Redis pooling built on redix and poolboy

Current section

Files

Jump to
redix_pool lib redix_pool.ex
Raw

lib/redix_pool.ex

defmodule RedixPool do
@moduledoc """
This module provides an API for using `Redix` through a pool of workers.
## Overview
`RedixPool` is very simple, it is merely wraps `Redix` with a pool of `Poolboy`
workers. All function calls get passed through to a `Redix` connection.
Please see the [redix](https://github.com/whatyouhide/redix) library for
more in-depth documentation. Many of the examples in this documentation are
pulled directly from the `Redix` docs.
"""
use Application
alias RedixPool.Config
@type command :: [binary]
@pool_name :redix_pool
def start(_type, _args) do
import Supervisor.Spec, warn: false
pool_options = [
name: {:local, @pool_name},
worker_module: RedixPool.Worker,
size: Config.get(:pool_size, 10),
max_overflow: Config.get(:pool_max_overflow, 1)
]
children = [
:poolboy.child_spec(@pool_name, pool_options, [])
]
opts = [strategy: :one_for_one, name: RedixPool.Supervisor]
Supervisor.start_link(children, opts)
end
@doc"""
Wrapper to call `Redix.command/3` inside a poolboy worker.
## Examples
iex> RedixPool.command(["SET", "k", "foo"])
{:ok, "OK"}
iex> RedixPool.command(["GET", "k"])
{:ok, "foo"}
iex> RedixPool.command(["INCR", "k"])
{:error, "ERR value is not an integer or out of range"}
"""
@spec command(command, Keyword.t) ::
{:ok, [Redix.Protocol.redis_value]} | {:error, atom | Redix.Error.t}
def command(args, opts \\ []) do
:poolboy.transaction(
@pool_name,
fn(worker) -> GenServer.call(worker, {:command, args, opts}) end,
RedixPool.Config.get(:timeout, 5000)
)
end
@doc"""
Wrapper to call `Redix.command!/3` inside a poolboy worker, raising if
there's an error.
## Examples
iex> RedixPool.command!(["SET", "k", "foo"])
"OK"
iex> RedixPool.command!(["GET", "k"])
"foo"
iex> RedixPool.command!(["INCR", "k"])
** (Redix.Error) ERR value is not an integer or out of range
"""
@spec command!(command, Keyword.t) :: Redix.Protocol.redis_value | no_return
def command!(args, opts \\ []) do
:poolboy.transaction(
@pool_name,
fn(worker) -> GenServer.call(worker, {:command!, args, opts}) end,
Config.get(:timeout, 5000)
)
end
@doc"""
Wrapper to call `Redix.pipeline/3` inside a poolboy worker.
## Examples
iex> RedixPool.pipeline([["INCR", "mykey"], ["INCR", "mykey"], ["DECR", "mykey"]])
{:ok, [1, 2, 1]}
iex> RedixPool.pipeline([["SET", "k", "foo"], ["INCR", "k"], ["GET", "k"]])
{:ok, ["OK", %Redix.Error{message: "ERR value is not an integer or out of range"}, "foo"]}
"""
@spec pipeline([command], Keyword.t) ::
{:ok, [Redix.Protocol.redis_value]} | {:error, atom}
def pipeline(args, opts \\ []) do
:poolboy.transaction(
@pool_name,
fn(worker) -> GenServer.call(worker, {:pipeline, args, opts}) end,
Config.get(:timeout, 5000)
)
end
@doc"""
Wrapper to call `Redix.pipeline!/3` inside a poolboy worker, raising if there
are errors issuing the commands (but not if the commands are successfully
issued and result in errors).
## Examples
iex> RedixPool.pipeline!([["INCR", "mykey"], ["INCR", "mykey"], ["DECR", "mykey"]])
[1, 2, 1]
iex> RedixPool.pipeline!([["SET", "k", "foo"], ["INCR", "k"], ["GET", "k"]])
["OK", %Redix.Error{message: "ERR value is not an integer or out of range"}, "foo"]
"""
@spec pipeline!([command], Keyword.t) :: [Redix.Protocol.redis_value] | no_return
def pipeline!(args, opts \\ []) do
:poolboy.transaction(
@pool_name,
fn(worker) -> GenServer.call(worker, {:pipeline!, args, opts}) end,
RedixPool.Config.get(:timeout, 5000)
)
end
end