Can you use the Redix_Pubsub library with Phoenix?

it doesn’t listen on port 4000 if I did this

defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
  import Supervisor.Spec

  children = [
    supervisor(MyApp.Repo, []),
    supervisor(MyAppWeb.Endpoint, []),
    worker(Redix.PubSub, []),
  ]

  {:ok, pubsub} = Redix.PubSub.start_link()

  Redix.PubSub.subscribe(pubsub, "my_channel", self())

  receive do
    {:redix_pubsub, ^pubsub, :subscribed, %{channel: "my_channel"}} -> :ok
  end

  receive do
    {:redix_pubsub, ^pubsub, :message, %{channel: "my_channel", payload: "hello"}} ->
    IO.puts "Received a message!"
  end

  opts = [strategy: :one_for_one, name: MyApp.Supervisor]
  result = Supervisor.start_link(children, opts)

  result
end

def config_change(changed, _new, removed) do
  MyAppWeb.Endpoint.config_change(changed, removed)
:ok
end
end

I mean this code

** (Mix) Could not start application my_app: MyApp.Application.start(:normal, []) returned an error: shutdown: failed to start child: MyApp.Registry
** (EXIT) an exception was raised:
** (UndefinedFunctionError) function MyApp.Registry.start_link/0 is undefined or private. Did you mean one of:

  * start_link/1

I added worker(MyApp.Registry, []) to children

Please show your code from your GenServer…

genserver

defmodule MyApp.Registry do
  use GenServer

  def start_link(opts) do
    GenServer.start_link(__MODULE__, :ok, opts)
  end

  def lookup(server, name) do
    GenServer.call(server, {:lookup, name})
  end

  def create(server, name) do
    GenServer.cast(server, {:create, name})
  end

  def init(:ok) do
      names = %{}
      refs = %{}

      {:ok, pubsub} = Redix.PubSub.start_link()
      Redix.PubSub.subscribe(pubsub, "my_channel", self())

      {:ok, {names, refs}}
  end

  def handle_call({:lookup, name}, _from, {names, _} = state) do
      {:reply, Map.fetch(names, name), state}
  end

  def handle_cast({:create, name}, {names, refs}) do
      if Map.has_key?(names, name) do
      {:noreply, {names, refs}}
      else
      {:ok, pid} = MyApp.Bucket.start_link([])
      ref = Process.monitor(pid)
      refs = Map.put(refs, ref, name)
      names = Map.put(names, name, pid)
      {:noreply, {names, refs}}
      end
  end

  def handle_info({:DOWN, ref, :process, _pid, _reason}, {names, refs}) do
      {name, refs} = Map.pop(refs, ref)
      names = Map.delete(names, name)
      {:noreply, {names, refs}}
  end

  def handle_info(_msg, state) do
      {:noreply, state}
  end
end

As mentionned in your error message, You need to pass an argument to start_link. Something like…

opts = whatever
worker(MyApp.Registry, [opts])

ok works, should i be putting the receivers in init function as well?

I would not use receive blocks… Instead, I would use handle_info to catch message. This is also described in the link mentionned before about GenServer.

i have 2 handle_info functions, as shown in the link mentioned. which should i be using?

You might start to see messages appears with

  def handle_info(msg, state) do
      inspect msg
      {:noreply, state}
  end
1 Like

yeap it works now thanks!