2016-08-31 4 views
0

ich wie ein einfaches Überwachungsmodul haben:Elixir Supervisor -init- dynamisch starten Kinder

defmodule Final.Users.Supervisor do 
    use Supervisor 

    def start_link, do: Supervisor.start_link(__MODULE__, :ok, name: __MODULE__) 

    def init(:ok) do  
    children = [ 
     worker(Final.UserServer, [], restart: :temporary) 
    ] 

    supervise(children, strategy: :simple_one_for_one) 
    end 

    def create_user(id), do: Supervisor.start_child(__MODULE__, [id]) 

end 

Was würde Ich mag auf Start tun, der Anwendung ist, Lookup-Datenbank und rufen create_user/1 für jeden Benutzereintrag in db.

Ich versuchte Process.send_after() ... in init aber es gibt Fehler (** (EXIT) Prozess versucht, sich selbst zu nennen)

Ist es überhaupt sinnvoll zu versuchen, dies in diesem Modul zu tun? Sollte ich einen anderen Mitarbeiter (genserver) einrichten, der dann DB abfragt und diesen Users.Supervisor.create_user/1 aufruft? Beispiel:

defmodule Final.Users.Starter do 
    alias Final.Repo 
    alias Final.Users.Supervisor, as: Sup 
    import Ecto.Query, only: [from: 2] 
    use GenServer 

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

    def init(:ok) do 
    Process.send_after(self(), :started, 0) 
    {:ok, %{}} 
    end 

    def handle_info(:started, %{}) do 
    query = from(p in "users", 
      select: p.id) 
    ids = Final.Repo.all(query) 
    Enum.each(ids, fn(x) -> Sup.create_user(x) end) 

    {:noreply, %{}} 
    end 
end 
+0

"Ich probierte Process.send_after() ... in init, aber es gibt Fehler (** (EXIT) Prozess versucht, sich selbst aufzurufen)" 'Process.send_after/3' in' init/1' funktioniert gut für mich in einem 'GenServer' (Ich kopierte deinen' Final.Users.Starter' und entfernte das Ecto- und Supervisor-bezogene Zeug). Können Sie den Stacktrace mit diesem Fehler posten? Dieser Fehler wird nur ausgelöst, wenn ein Prozess versucht, eine 'GenServer.call' an sich selbst zu senden (was zu einem Deadlock führen wird). – Dogbert

Antwort

1

Sie können nicht dynamisch Kinder in der init/1 Rückruf Vorgesetzten beginnen, da diese Funktion die Kinder die technischen Werte des neu gestarteten Überwachungsprozeß zurückgibt. Mit anderen Worten, der Supervisor weiß nicht, wie er Kinder startet, bevor dieser Callback zurückkehrt.

Das Einrichten eines GenServers nur für einige Initialisierungsarbeiten scheint zu viel zu sein. Eine bessere Idee wäre es, einen temporären Prozess zu starten, um den Job und den Abbruch sofort zu erledigen.

Zu diesem Zweck können Sie ein Task verwenden:

Task.start_link(fn -> 
        query = from(p in "users", select: p.id) 
        ids = Final.Repo.all(query) 
        Enum.each(ids, fn(x) -> Sup.create_user(x) end) 
       end) 

Eine solche Aufgabe aus Ihrer Anwendung Hauptmodul laichen werden könnte. Beachten Sie jedoch, dass, wenn diese Aufgabe fehlschlägt, ein Beendigungssignal an den Aufrufer gesendet wird.

Verwandte Themen