Elixir: Loop the actor to rerun itself

443 views Asked by At

I am making an master-worker application. The Master code is as follows. This code asynchronously calls workers in start_link. Once the workers are done with their work, they report to master using handle_cast asynchronous call. After this I intend keep the master actor 'ON' so that it can re-spawn the new worker Actors(like it did in first start_link call.). However, the master stops once all the worker actors are done with their work. This stackoverflow post mentions using recursive call but I am not able to do it with Genserver. Is there any method in Genserver to achieve it?

defmodule Bitcoin.MasterNode do
use GenServer

def start_link(opts) do
    {:ok, pid} = GenServer.start_link(__MODULE__,:ok, opts)
    start_workers(----perform some task asynchronously----)
    {:ok, pid}
end

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

#callbacks
def init(:ok) do
    names = []
    {:ok, names}
end

def handle_cast({:set_message, name},names) do
    names = names ++ name
    IO.puts name
    {:noreply,names}
end

end

Edit: I am running application on distributed mode i.e, master is also connected to external worker nodes. If Master dies, the connections also dies out. The intention is to keep the master node with same PID to run infinite times.

1

There are 1 answers

2
Aleksei Matiushkin On

If I properly understood your intent, you want to restart the whole process as soon as all children are done. If that’s true, one should use OTP features instead of inventing their own wheels :)

Just extend the supervision tree with one more supervisor, that would be supervising your “master” (Bitcoin.MasterNode,) and you are all set.

What will happen:

  1. MasterSupervisor starts;
  2. MasterSupervisor transparently starts MasterNode as a worker with a :one_for_one strategy;
  3. MasterNode acts exactly as it does now;
  4. as soon as all workers are done, MasterNode dies, which is fine;
  5. once it’s child MasterNode has died, MasterSupervisor will automatically restart it due to it’s strategy.

To keep track of GenServer despite whether is was respawned or not, one should use named servers instead of just operating PIDs:

GenServer.start_link(__MODULE__,:ok, name: MyWorker)