2017-09-11 3 views
0

J'essaie de configurer un arbre de supervision pour une application de planificateur (remarque en utilisant la syntaxe Elixir 1.5). L'application devrait travail afin que:Comment passer des arguments à: simple_one_for_one GenServer pour initialiser l'état

  • bottes d'application avec un registre & le superviseur du planificateur
  • Les bottes SchedulerSupervisor et permet aux enfants d'être ajoutés dynamiquement via le rappel start_child. Cela prend les arguments d'initialisation qui sont utilisés pour construire l'état de planification. Le planificateur, à l'initialisation, enregistre son nom dans le registre et s'initialise avec une structure qui contient l'état (le planificateur a alors des fonctions de manipulation des horaires, mais cela ne concerne pas le problème que je rencontre).

Si je ne suis pas passer les arguments, je peux obtenir ce travail - les annexes créées ne sont pas enregistrés, et je dois modifier l'état après la création. Dès que j'essaie d'ajouter des arguments, les erreurs du système - je sais que c'est juste une erreur de syntaxe de ma part, mais je ne peux pas, pour la vie de moi, comprendre ce que je fais de mal. Je n'ai pas trouvé les docs terriblement utiles ici, et j'ai essayé de copier et de modifier des exemples de GH, GH Gists et d'articles en ligne, mais je n'arrive pas à le faire fonctionner.

configuration actuelle - idéalement, je voudrais passer id, period et targets comme arguments à start_child, mais ne peux même pas le faire fonctionner avec un seul argument, donc juste coller avec celui jusqu'à ce que je peux le faire fonctionner:

L'application:

defmodule Assay.Application do 
    use Application 

    def start(_type, _args) do 
    children = [ 
     {Assay.SchedulerSupervisor, []}, 
     {Registry, keys: :unique, name: Assay.Scheduler.Registry} 
    ] 

    opts = [strategy: :one_for_all, name: Assay.Supervisor] 
    Supervisor.start_link(children, opts) 
    end 
end 

Le superviseur:

defmodule Assay.SchedulerSupervisor do 
    use Supervisor 

    @name Assay.SchedulerSupervisor 

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

    def start_schedule(id) do 
     Supervisor.start_child(@name, [id]) 
    end 

    def init(_) do 
     Supervisor.init([Assay.Scheduler], [strategy: :simple_one_for_one, name: @name]) 
    end 
end 

Th e GenServer (seules les fonctions d'initialisation pertinentes indiquées)

defmodule Assay.Scheduler do 
    use GenServer 
    alias Assay.Scheduler 
    require Logger 

    defstruct targets: [], period: 60_000, id: nil, active: false 

    def start_link(id) do 
     GenServer.start_link(__MODULE__, [id], [name: via_tuple(id)]) 
    end 

    def init([id]) do 
     Logger.info "starting a new #{__MODULE__} with id #{id}" 
     {:ok, %Scheduler{id: id}} 
    end 
end 

modifier: erreur réelle pourrait aider - je peux voir que les args ont tort, je ne peux pas comprendre pourquoi:

{:error, 
{:EXIT, 
    {:undef, 
    [{Assay.Scheduler, :start_link, [[], 1], []}, 
    {:supervisor, :do_start_child_i, 3, [file: 'supervisor.erl', line: 381]}, 
    {:supervisor, :handle_call, 3, [file: 'supervisor.erl', line: 406]}, 
    {:gen_server, :try_handle_call, 4, [file: 'gen_server.erl', line: 636]}, 
    {:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 665]}, 
    {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 247]}]}}} 
+0

Quelle est l'erreur exacte que vous obtenez? – Dogbert

+0

ah, désolé, message d'erreur enregistré ajouté @Dogbert – DanCouper

+0

Etes-vous sûr que c'est le message d'erreur pour le code dans la question? Vous ne passez pas 60000 à start_child mais c'est dans le message d'erreur. – Dogbert

Répondre

4

Pour :simple_one_for_one superviseurs, Supervisor.start_child appelle la fonction start avec les arguments qui lui sont attribués avec les arguments spécifiés dans la spécification enfant. Lorsque vous utilisez Supervisor.init, la spécification enfant est extraite de la fonction child_spec/1 du module dans Elixir 1.5. Puisque vous utilisez GenServer et ne pas spécifier une fonction de démarrage personnalisée et [] est passé à child_spec/1, ce defaults to[[]] qui signifie que votre fonction finit par être appelé avec deux arguments, [] et 1 si le id est 1 et vous obtenez une erreur de fonction non définie .

Vous pouvez corriger cela en dire explicitement que vous ne voulez pas le GenServer de fournir des arguments à la fonction de démarrage dans child_spec en changeant

use GenServer 

à

use GenServer, start: {__MODULE__, :start_link, []} 

Maintenant, la fonction sera appelé correctement, avec un seul argument, qui sera le id.

IO.inspect Assay.SchedulerSupervisor.start_link [] 
IO.inspect Assay.SchedulerSupervisor.start_schedule 12 

imprimera:

{:ok, #PID<0.82.0>} 
[info] starting a new Elixir.Assay.Scheduler with id 12 
{:ok, #PID<0.83.0>} 
+0

Fantastique, merci. J'ai trouvé les documents très peu clairs à ce sujet (creuser à travers les problèmes de GitHub et semble qu'il y avait une discussion sur leur étant peu clair lorsque DynamicSupervisor a été proposé l'année dernière), a beaucoup plus de sens maintenant – DanCouper