I am having a GenServer running that updates its state after every five seconds. I need to send that state after every 5 seconds to another GenServer but I really don’t want to hard code the PID of other GenServer as the name might change in the future.
Is there any way that the receiver knows about the sender but the sender doesn’t know about the receiver?
My Code
defmodule Sender do
use GenServer
def start_link(process_name) do
GenServer.start_link(__MODULE__, [[], process_name], name: process_name)
end
# server
def init([state, process_name]) do
schedule_state_send(process_name)
{:ok, state}
end
def handle_info({:table_state, process_name}, state) do
IO.puts("Current state of #{inspect(process_name)} is #{inspect(state)}")
schedule_state_send(process_name)
sending_state_to_view(process_name, state)
state = []
{:noreply, state}
end
def schedule_state_send(process_name) do
Process.send_after(self(), {:table_state, process_name}, 5_000)
end
def sending_state_to_view(process_name, state) do
# code goes here
end
end
My Reciever GenServer
How can it receive the state that the sender has to send continuously.
defmodule Reciever do
use GenServer
# client
def start_link(process_name) do
GenServer.start_link(__MODULE__, [], name: process_name)
end
# server
def init(view_state) do
{:ok, view_state}
end
end
There are few different approaches and the simplest one I can think of is to send PID from one process to another:
defmodule Sender do
use GenServer
def register(name), do: GenServer.call(name, {:register, self()})
def start_link(process_name) do
GenServer.start_link(__MODULE__, %{pid: nil}, name: process_name)
end
# server
def init(state) do
{:ok, state}
end
def handle_call({:register, pid}, _caller, _state) do
{:reply, :ok, %{pid: pid}, {:continue, :schedule}}
end
def handle_info(:ping, %{pid: nil} = state), do: {:noreply, state}
def handle_info(:ping, %{pid: pid} = state) when is_pid(pid) do
send(pid, :ping)
{:noreply, state, {:continue, schedule}}
end
def handle_continue(:schedule, state) do
Process.send_after(self(), :ping, 5_000)
{:noreply, state}
end
end
And then
defmodule Receiver do
use GenServer
require Logger
# client
def start_link(sender) do
GenServer.start_link(__MODULE__, sender)
end
# server
def init(sender) do
Sender.register(sender)
{:ok, []}
end
def handle_info(:ping, state) do
Logger.info("Received ping")
{:noreply, state}
end
end
PubSub! Phoenix.PubSub is very good, and can be used entirely server-side … you can subscribe to topics and push events to channels entirely on the server side. I use this extensively to publish change notifications from domain modules that are picked up by GenServers and even LiveViews to change their assigns.
Related to this is the Registry module, which can allow you to register a process on an arbitrary name and look it up …
You can also look into process groups which allow 1 or more processes to share a name, and then you broadcast messages to all members of them, with the conceit that group names are less likely to change than individual names.
The sender can have multiple instances, means that there can be multiple senders each having their own process id. How will this code identify which process is sending information. I am not getting the code.