ananthakumaran / redix_sentinel

Redix with sentinel support
MIT License
5 stars 2 forks source link

Can I use this without sentinel? #2

Open rlipscombe opened 6 years ago

rlipscombe commented 6 years ago

Let's say I want to test something locally, and I only have a single redis instance, with no sentinel. Can I use this without a sentinel? Note that we are using sentinel in production, so I'd prefer to use RedixSentinel for that.

I tried:

{:ok, redis} = RedixSentinel.start_link([], [host: redis_host, port: 6379, database: 0])
{:ok, "PONG"} = RedixSentinel.command(redis, ["PING"])

...but it failed with:

** (EXIT from #PID<0.77.0>) an exception was raised:
    ** (KeyError) key :sentinels not found in: [log: [disconnection: :error, failed_connection: :error, reconnection: :info, sentinel_connection: :debug], backoff_initial: 500, backoff_max: 30000, role: "master", verify_role: 0]
        (elixir) lib/keyword.ex:377: Keyword.fetch!/2
        (redix_sentinel) lib/redix_sentinel.ex:231: RedixSentinel.find_and_connect/1
        (redix_sentinel) lib/redix_sentinel.ex:153: RedixSentinel.connect/2
        (connection) lib/connection.ex:622: Connection.enter_connect/5
        (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3

Related: It doesn't appear that I can mix RedixSentinel.start_link with Redix.command, which would be the other way I'd try to make the interesting code agnostic about whether I'm using a sentinel or not (because I could then use Redix.start_link when I knew I wasn't using a sentinel). That doesn't work either.

ananthakumaran commented 6 years ago

We had a similar situation, but at the end I decided to use sentinels in development also.

You could write a thin wrapper around Redix & RedixSentinel and dispatch based on some config. Probably some macro could make it easier

defmodule Redis
  def command!()
    if sentinel do
      RedixSentinel.command!()
    else
      Redix.command!()
    end
  end

  def start_link()
    ..
  end
end

I will keep all the api except start_link same(it's documented and some of my projects depend on this). I am not convinced enough to add(or not sure how to go about it) such functionality in RedixSentinel yet.

mertonium commented 6 years ago

@rlipscombe - if your still interested, I get around this by

  1. Having a thin redis wrapper specific to my app (like @ananthakumaran said). I.e.

    defmodule MyApp.RedisWrapper do
    @redis_lib Application.get_env(:my_app, :redis_lib)
    
    def get(conn, key) do
    @redis_lib.command(conn, ["GET", key])
    end 
    end
  2. Then, in my mix configs I set which redis library to use. In config/dev.exs:

    config :my_app, redis_lib: Redix

    and in config/prod.exs:

    config :my_app, redis_lib: RedixSentinel
  3. With regard to the calling start_link, in my case I do it in a supervisor tree so I added a little function called child_tuple to MyApp.RedisWrapper that checks @redis_lib and passes back the right tuple (I'd elaborate more with code, but my use case is super-specific which I think would distract).