2017-09-17 3 views
0

Ich mache eine Master-Worker-Anwendung. Der Mastercode ist wie folgt. Dieser Code ruft Arbeiter asynchron in start_link. Sobald die Arbeiter mit ihrer Arbeit fertig sind, melden sie sich unter Verwendung des asynchronen Aufrufs handle_cast. Danach beabsichtige ich, den Hauptdarsteller auf 'ON' zu halten, damit er die neuen Arbeiter-Schauspieler wieder spawnen kann (wie es in dem ersten Anruf start_link tat.). Der Meister stoppt jedoch, sobald alle Arbeiter mit ihrer Arbeit fertig sind. Diese stackoverflow Post erwähnt mit rekursiven Aufruf, aber ich bin nicht in der Lage, es mit Genserver zu tun. Gibt es eine Methode in Genserver, um es zu erreichen?Elixir: Loop der Schauspieler, um sich selbst zu wiederholen

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 

Ende

Edit: I Anwendung leite auf verteilten Modus heißt, ist Master auch an externe Arbeiter Knoten verbunden. Wenn der Meister stirbt, erlöschen auch die Verbindungen. Die Absicht ist, den Master-Knoten mit der gleichen PID unendlich lange laufen zu lassen.

+2

Bitte verwenden Sie keine Code-Formatierung für Betonung, Verwendung Betonung für die Betonung (überprüfe meine Änderungen, um zu sehen, wie.) – mudasobwa

+0

Sie brauchen keinen rekursiven Aufruf, um einen GenServer am Leben zu erhalten. Ein GenServer bleibt am Leben, bis er explizit gestoppt wird (oder aufgrund eines Fehlers abstürzt). Ich sehe keinen Code in Ihrem Code-Snippet, der den GenServer stoppen würde. Stoppen 'start_workers' diesen GenServer? – Dogbert

+2

"Die Absicht ist, den Master-Knoten mit der gleichen PID unendlich viele Male laufen zu lassen." - Das ist unmöglich. Benutzt stattdessen benannte Server. Bei Serverneustarts werden die Namen nicht geändert. – mudasobwa

Antwort

2

Wenn ich Ihre Absicht richtig verstanden habe, möchten Sie den gesamten Prozess neu starten, sobald alle Kinder fertig sind. Wenn das stimmt, sollte man OTP-Funktionen verwenden, anstatt ihre eigenen Räder erfinden :)

einfach die Aufsicht Baum mit einem weiteren Supervisor erweitern, die Ihr „Master“ würde die Überwachung (Bitcoin.MasterNode,) und Sie alle gesetzt .

Was passiert:

  1. MasterSupervisor beginnt;
  2. MasterSupervisor beginnt transparent MasterNode als ein Arbeiter mit einer :one_for_one Strategie;
  3. MasterNode wirkt genau so wie es jetzt tut;
  4. sobald alle Arbeiter fertig sind, MasterNodestirbt, was in Ordnung ist;
  5. Sobald es Kind ist MasterNode ist gestorben, MasterSupervisorwird es automatisch aufgrund seiner Strategie neu starten.

Um den Überblick über GenServer trotz zu halten, ob oder nicht ist respawned wurde, sollte man named servers statt nur Betriebs PID s verwenden:

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

Mein schlechtes. Ich möchte auch, dass die Anwendung im verteilten Modus ausgeführt wird. Wenn der Meister stirbt, werden auch externe Arbeiter sterben. Ich habe die Frage aktualisiert. Können wir noch etwas Elixier-Magie tun? – COSTA

+0

@mudasobwa: Ich bin neu bei Erlang (und Elixir) und verstehe das Konzept der Supervisor nicht ganz. Sollte der Supervisor den Prozess nicht neu starten, wenn der Prozess * fehlgeschlagen ist, anstatt eine erfolgreiche Beendigung. OP hat in Kommentaren erwähnt, dass die Worker-Threads vor dem Sterben "Bitcoin.MasterNode.set_message" aufrufen. Wenn ich bei ihm wäre, hätte ich einen neuen Prozess von "set_message" erzeugt, um den alten Prozess zu ersetzen. –

Verwandte Themen