jakub-zawislak

jakub-zawislak

Subscribe to Phoenix.PubSub from another application

I’m new to distributed elixir.

I have two clean installations of Phoenix 1.4.2 - apps named A and B. I’m running these with --sname option. I can run command from another application using :rpc.call. Can I subscribe to Phoenix.PubSub from another app?

I have tried:

iex(a@MacBook-Pro)1> Node.connect :"b@MacBook-Pro"
iex(a@MacBook-Pro)2> Phoenix.PubSub.subscribe(B.PubSub, "topic")
# throws argument error - :ets.lookup(B.PubSub, :subscribe)

Should it be somehow wrapped by a GenServer on the B side and used with Node.spawn_link? Is there some easier solution? First I wanted to broadcast messages between two apps installed on same server using websockets but then I thought there should be an easier method.

Most Liked

jakub-zawislak

jakub-zawislak

Maybe someone will be interested in my final implementation of the subscriber module

defmodule B.Worker do
  use GenServer

  @reconnect_interval 1_000

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

  def init(:ok) do
    Process.send_after(self(), :join_pg2, 0)

    {:ok, %{}}
  end

  def handle_info(:join_pg2, state) do
    node_name = :"a@MacBook-Pro"

    case Node.connect(agent_node) do
      true ->
        if :group_name not in :pg2.which_groups() do
          :global.sync()
          :ok = :pg2.join(:group_name, self())
        end

        Node.monitor(node_name, true)

        {:noreply, state}

      false ->
        Process.send_after(self(), :join_pg2, @reconnect_interval)

        {:noreply, state}
    end
  end

  # from Node.monitor
  def handle_info({:nodedown, _node}, state) do
    Process.send_after(self(), :join_pg2, 0)

    {:noreply, state}
  end

  def handle_info(msg, state) do
    IO.inspect msg

    {:noreply, state}
  end
end

blatyo

blatyo

Conduit Core Team

I’m not super familiar with the implementation details, but I’ll try to describe it conceptually and hopefully that’ll help.

Phoenix.PubSub works, by creating a cluster of different nodes. You need to start a Phoenix.PubSub process on every node in the cluster. You can specify an adapter, which allows Phoenix.PubSub to discover what other nodes are available to connect to. In the case of the redis adapter, each node will connect to redis and messages will be sent through that. In the case of PG2 (the default), Phoenix.PubSub will connect with other Phoenix.PubSub processes on any of the nodes already clustered by the nodes being connected.

So, you’ve correctly connected the nodes. But it looks like you’ve not started a Phoenix.PubSub process. So, when you call Phoenix.PubSub.subscribe/2, the process that would’ve setup stuff locally on the current node hasn’t done so and you’re getting an error about a lookup on an ets table not existing.

I think in the simple iex session you’re just missing something like:

Phoenix.PubSub.PG2.start_link(name: B.PubSub)

jakub-zawislak

jakub-zawislak

I figured it out without the Phoenix.PubSub. I think it’s all I need.

Create pg2 group in A

defmodule A.Application do
  def start(_type, _args) do
    :pg2.create :some_group
    # ...
  end

Connect to group in B

defmodule B.Application do
  def start(_type, _args) do
    children = [
      # ...
      {B.Worker, []},
    ]
    # ...
  end
defmodule B.Worker do
  use GenServer

  def start_link(opts) do
    {:ok, pid} = GenServer.start_link(__MODULE__, :ok, opts)

    true = Node.connect(:"a@MacBook-Pro")
    :ok = :pg2.join(:some_group, pid)

    {:ok, pid}
  end
end

Send message in A

iex(a@MacBook-Pro)1> [pid] = :pg2.get_members :some_group
iex(a@MacBook-Pro)2> send(pid, :hello) 

Handle messages from A in B

defmodule B.Worker do
  def handle_info(msg, state) do
    IO.inspect msg

    {:noreply, state}
  end
end

Where Next?

Popular in Questions Top

9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
earth10
Hi, I’m just starting to build a side-project with Elixir and Phoenix and doing some basic test with Elixir alone. What strikes me is th...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
New
nobody
Hi! In PHP: $SERVER['SERVERADDR'] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Other popular topics Top

marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 42842 311
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I fore...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31107 143
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New

We're in Beta

About us Mission Statement