Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where do I store the PID for longrunning child processes?

Tags:

elixir

I'm writing a simple web application that is using Exredis as a database. The Exredis docs say to initialize the client with:

{:ok, conn} = Exredis.start_link

My question is, where do I put conn? Right now I'm calling Exredis.start_link\1 at the top of every function that needs to make a DB query, but that feels both noisy and inefficient. I can pass the conn in, but that just moves the problem up to my routers.

I'd like to start it once as my main application starts and simply reuse the single connection throughout my app. I can add it as a worker to my supervisor, but I can't figure out how to access the PID in the rest of my application.

like image 621
Ben Cates Avatar asked Mar 13 '23 10:03

Ben Cates


1 Answers

Instead of passing conn around I'd suggest that you create a single module that deals with redis. There're two ways you might want to do it (the second one is preferred):

1. Each time you query redis a new connection is started and closed:

    defmodule Redis do
        @redis_host "192.168.0.10"
        @redis_port 6379

        def query( ... ) do
            {:ok, conn} = Exredis.start_link( @redis_host, @redis_port )
            r = Exredis.query( conn, ... )
            Exredis.stop( conn )
            r
        end
    end

2. Better yet you wrap Exredis in a GenServer (Preferred solution):

    defmodule Redis do
        use GenServer

        @redis_host "192.168.0.10"
        @redis_port 6379

        # External API

        def start_link( state ) do
            GenServer.start_link( __MODULE__, state, name: __MODULE__ )
        end

        def query( ... ) do
            GenServer.call __MODULE__, { :query, ... }
        end

        # GenServer implementation

        def init( state ) do
            {:ok, conn} = Exredis.start_link( @redis_host, @redis_port )

            # conn becomes state available in handle_call / terminate
            {:ok, conn}
        end

        def handle_call( { :query, ... }, conn ) do
            r = Exredis.query( conn, ... )
            { :reply, r, conn }
        end

        def terminate( _reason, conn ) do
            Exredis.stop( conn )
        end
    end

You add the above GenServer to your supervisor (pass it nil as initial state). And then you stick to the external API. You never deal with the GenServer directly which makes it easier to change and evolve your module in the future. You can read more about GenServers here.

like image 196
krychu Avatar answered Apr 02 '23 18:04

krychu