Does anyone how to use redis with Genserver?

I have Genserver which returns the data from the database. Now I want that data to store in a key-value manner in my Redis. But I’m not sure how to use this. I’m using this library https://github.com/whatyouhide/redix


defmodule Gorm.Database do
  use GenServer
  alias Gorm.Accounts
  alias Gorm.Accounts.User
  alias Gorm.Repo

  def start_link(args) do
    GenServer.start_link(__MODULE__, [])
  end

  def init(list) do
    {:ok, []}
  end

  def list(pid) do
    GenServer.call(pid, :list)
  end

  def handle_call(:list, _from, state) do
    my_models = Accounts.list_users()

    {:reply, my_models, state}
  end
end

# alias Gorm.Database
# Gorm.Database
# iex(4)> Database.start_link([])
# {:ok, #PID<0.457.0>}
# iex(5)> {:ok, pid} = Database.start_link([])
# {:ok, #PID<0.459.0>}
# iex(6)> {:ok, pid} = Database.start_link([])
# {:ok, #PID<0.461.0>}
# iex(7)> pid
# #PID<0.461.0>
# iex(8)> Database.list(pid)
# [debug] QUERY OK source="users" db=16.6ms decode=3.0ms queue=22.2ms idle=9049.3ms
# SELECT u0."id", u0."email", u0."name", u0."inserted_at", u0."updated_at" FROM "users" AS u0 []
# [
#   %Gorm.Accounts.User{
#     __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
#     email: "ssaadamdkm@mfkmk.com",
#     id: 1,
#     inserted_at: ~N[2020-02-18 18:29:26],
#     name: "siddhantsingh",
#     updated_at: ~N[2020-02-18 18:29:26]
#   }
# ]
# iex(9)>

Can someone help me with this?

What specifically are you not sure about, or what problem did you run into?

Did You read the Redix README? It looks easy to setup an Elixir Redis client.

Like in general how do I use it? i’m not sure how to approach this

Because right now in start_link function which takes list as a argument. Basically I’m confused about start link function what arguments and how do I call this?

Redix.start_link(
  host: "example.com", port: 9999, ssl: true,
  socket_opts: [
    customize_hostname_check: [
      match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
    ]
  ]
)

Valid options are described in the documentation of Redix.start_link/1

1 Like

Yes But I want to know how I can implement it. Because that I have implemented with Supervisor and this one is with genserver.

defmodule Gorm.RedisPool do
  use Supervisor

  @redis_connection_params host: Application.get_env(:gorm, :redis_host),
                           password: Application.get_env(:gorm, :redis_password),
                           port: Application.get_env(:gorm, :redis_port),
                           database: Application.get_env(:gorm, :redis_database)

  def start_link(_args) do
    Supervisor.start_link(__MODULE__, [])
  end


  #Fault Tolerance
  # This is just ensuring that phoenix keeps the cache running.

  def init([]) do
    pool_opts = [
      name: {:local, :redix_poolboy},
      worker_module: Redix,
      size: 10,
      max_overflow: 5,
    ]

    children = [
      :poolboy.child_spec(:redix_poolboy, pool_opts, @redis_connection_params)
    ]

    Supervisor.init(children, strategy: :one_for_one, name: __MODULE__)
  end

  def command(command) do
    :poolboy.transaction(:redix_poolboy, &Redix.command(&1, command))
  end

  def pipeline(commands) do
    :poolboy.transaction(:redix_poolboy, &Redix.pipeline(&1, commands))
  end
end

Look

defmodule Gorm.Database do
  use GenServer
  alias Gorm.Accounts
  alias Gorm.Accounts.User
  alias Gorm.Repo

  def start_link(args) do
    GenServer.start_link(__MODULE__, [])
  end

  def init(list) do
    {:ok, []}
  end

  def list(pid) do
    GenServer.call(pid, :list)
  end

  def handle_call(:list, _from, state) do
    my_models = Accounts.list_users()

    {:reply, my_models, state}
  end
end

How you can implement what?

For which I start this thread

get/set ? https://github.com/whatyouhide/redix#usage

Redix.command(conn, ["SET", "mykey", "foo"])
#=> {:ok, "OK"}
Redix.command(conn, ["GET", "mykey"])
#=> {:ok, "foo"}

from a quick look you would call Gorm.RedisPool.command(["SET", "mykey", "foo"]) and/or Gorm.RedisPool.command(["GET", "mykey"])

1 Like

Hey thanks for commenting

defmodule Gorm.Database do
  use GenServer
  alias Gorm.Accounts
  alias Gorm.Accounts.User
  alias Gorm.Repo

  def start_link(args) do
    GenServer.start_link(__MODULE__, [])
  end

  def init(list) do
    {:ok, []}
  end

  def list(pid) do
    GenServer.call(pid, :list)
  end

  def get(:list, key) do
    Genserver.call(list, {:get, key})
  end

  def set(:list, key, value) do
    GenServer.call(list, {:set, key, value})
  end

  def handle_call(:list, _from, state) do
    my_models = Accounts.list_users()

    {:reply, my_models, state}
  end
end

Is this approach is correct?

Do you not know how you get connections into the pool? Out of the pool? How to get/set values in redis?

What exactly do you not know how to implement?

Please try to ask more specific questions, and show relevant code what you already have.

2 Likes

Yes I’m new to Genserver and Redis. That’s why I’m struggling. I don’t know how the flow work. Just learning this by implementing it.

figure out(and debug) the individual building blocks first - and then figure out how to put all together…

But the problem with this I think I have to define the private function for get and set. Maybe I have to add a case to it

It is wrong, and You didn’t put the corresponding handle_call callback.

And You are using :list, as if it was list…

And You are mixing API with callbacks. Do You know order is very important?

You should probably starts by reading some docs… on GenServer.

But it’s a good start, You need to implement a get and set functions in the genserver.

It would be nice for get to check first if the key exists in Redis, that would solve your caching problem.

def get(pid, key) do
  # check if key exists
  # if not call the server, and persists the returned value in redis
end

Of course You need to fill the blank.

defmodule Gorm.Database do
  use GenServer
  alias Gorm.Accounts
  alias Gorm.Accounts.User
  alias Gorm.Repo

  def start_link(args) do
    GenServer.start_link(__MODULE__, [])
  end

  def init(list) do
    {:ok, []}
  end

  def list(pid) do
    GenServer.call(pid, :list)
  end

  def get(pid, key) do
    GenServer.call(pid, {:get, key})
  end

  def set(pid, key, value) do
    GenServer.call(pid, {:set, key, value})
  end

  def handle_call(:list, _from, state) do
    my_models = Accounts.list_users()

    {:reply, my_models, state}
  end
end

Implemented this much. Doing the setup for redis

But we are not asking for that. We are asking what are you trying to do exactly. By saying “to implement GenServer and Redis” you tell us exactly nothing.

EDIT: What I mean is you should have answered with “I am trying to have my app supervise the connection to Redis and to read and write basic data to it”. This is a potential answer for us with which we can help you.

1 Like

It’s difficult to get started, as lots of things don’t make sense. But you need to give yourself time and understand the fundamentals first, then you will be able to build up from there. I am sorry but it’s not really possible to help you out with this, because we don’t know what you want to achieve, and which problems you are encountering.

My honest suggestion would be to take a step back, and tackle one thing at a time. It looks like you know Elixir basics, so you can move from there. You can then tackle OTP, and focus on smaller problems until you understand GenServers and such. Then you’ll be ready to move on to using them for stuff like Redis or databases.

As you learn, should you hit something specific that you don’t understand or that you cannot fix, you will be able to explain your specific problem, and lots of people here can help you with that. But you’ll need to specify well what you are trying to do, and where you hit problems.

We all went through this, and we all asked naive questions and got help from more experienced people, so do not feel ashamed to ask. But you cannot expect people to write your code for you from scratch.

8 Likes