Real-world usage

Redix is a low-level driver, but it’s still built to handle most stuff thrown at it.

Redix is built to handle multiple Elixir processes sending commands to Redis through it at the same time. It takes advantage of TCP being a full-duplex protocol (bytes are sent in both directions, often at the same time) so that the TCP stream has bytes flowing in both directions (to and from Redis). For example, if two Elixir processes send a PING command to Redis via Redix.command/2, Redix will send both commands to Redis but will concurrently start listening for the reply to these commands; at a given point, both a PING command as well as the PONG response to a previous PING could be flowing in the TCP stream of the socket that Redix is using.

There’s a few different ways to use Redix and to pool connections for better high-load support.

Single named Redix instance

For many applications, a single global Redix instance is enough. This is true especially for applications where requests to Redis are not mapping one-to-one to things like user requests (that is, a request for each user). A common pattern in these cases is to have a named Redix process started under the supervision tree:

children = [
  {Redix, name: :redix}
]

Once Redix is started and registered, you can use it with the given name from anywhere:

Redix.command(:redix, ["PING"])
#=> {:ok, "PONG"}

Note that this pattern extends to more than one global (named) Redix: for example, you could have a Redix process for handling big and infrequent requests and another one to handle short and frequent requests.

Name-based pool

When you want to have a pool of connections, you can start many connections and register them by name. Say you want to have a pool of five Redis connections. You can start these connections in a supervisor under your supervision tree and then create a wrapper module that calls connections from the pool. The wrapper can use any strategy to choose which connection to use, for example a random strategy.

defmodule MyApp.Redix do
  @pool_size 5

  def child_spec(_args) do
    # Specs for the Redix connections.
    children =
      for i <- 0..(@pool_size - 1) do
        Supervisor.child_spec({Redix, name: :"redix_#{i}"}, id: {Redix, i})
      end

    # Spec for the supervisor that will supervise the Redix connections.
    %{
      id: RedixSupervisor,
      type: :supervisor,
      start: {Supervisor, :start_link, [children, [strategy: :one_for_one]]}
    }
  end

  def command(command) do
    Redix.command(:"redix_#{random_index()}", command)
  end

  defp random_index() do
    rem(System.unique_integer([:positive]), 5)
  end
end

You can then start the Redix connections and their supervisor in the application’s supervision tree:

def start(_type, _args) do
  children = [
    MyApp.Redix,
    # ...other children
  ]

  Supervisor.start_link(children, strategy: :one_for_one)
end

And then use the new wrapper in your application:

MyApp.Redix.command(["PING"])
#=> {:ok, "PONG"}