2015-07-14 24 views
7

Elixir denetçileriyle gerçekten uğraşıyorum ve bunları nasıl kullanabileceğimi anlamaya çalışıyorum. Temel olarak, sadece iletileri gönderebileceğim denetlenen bir Task başlatmaya çalışıyorum. proje giriş noktası ileElixir Süpervizörleri - Nasıl Denetimli Görev Adlandırıyorsunuz

defmodule Run.Command do 
    def start_link do 
    Task.start_link(fn -> 
     receive do 
     {:run, cmd} -> System.cmd(cmd, []) 
     end 
    end) 
    end 
end 

:

Yani şu var bu noktada

defmodule Run do 
    use Application 

    # See http://elixir-lang.org/docs/stable/elixir/Application.html 
    # for more information on OTP Applications 
    def start(_type, _args) do 
    import Supervisor.Spec, warn: false 

    children = [ 
     # Define workers and child supervisors to be supervised 
     worker(Run.Command, []) 
    ] 

    # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html 
    # for other strategies and supported options 
    opts = [strategy: :one_for_one, name: Run.Command] 
    Supervisor.start_link(children, opts) 
    end 
end 

, ben bile doğru olanı kullanıyorum emin hissetmiyorum (Task özellikle). Temel olarak, tek istediğim bir süreç veya görev ya da GenServer ya da uygulama başladığında ne olursa olsun doğru olan her şey bir System.cmd(cmd, opts) yapacaktır. Bu görevin veya sürecin denetlenmesini istiyorum. {:run, "mv", ["/file/to/move", "/move/to/here"]} gibi bir {:run, cmd, opts} iletisini gönderdiğimde, bu komutu çalıştırmak için yeni bir görev veya işlem oluşturmasını istiyorum. Benim kullanımım için, yanıtı görevden geri almam bile gerekmiyor, sadece yürütmek için ihtiyacım var. Nereye gideceğinize dair herhangi bir rehber yardımcı olabilir. Başlarken kılavuzu okudum ama dürüst olmak gerekirse bana daha fazla kafa karıştırdı çünkü ne yaptığınızı yapmaya çalıştığımda asla uygulamada olduğu gibi çıkıyor.

Sabrınız için teşekkür ederiz. şöyle yürütmek için

defmodule Run do 
    use Application 

    def start(_, _) do 
    import Supervisor.Spec, warn: false 

    children = [worker(Run.Command, [])] 
    Supervisor.start_link(children, strategy: :one_for_one) 
    end 
end 

defmodule Run.Command do 
    use GenServer 

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

    def run(cmd, opts) when is_list(opts), do: GenServer.call(__MODULE__, {:run, cmd, opts}) 
    def run(cmd, _), do: GenServer.call(__MODULE__, {:run, cmd, []}) 

    def handle_call({:run, cmd, opts}, _from, state) do 
    {:reply, System.cmd(cmd, opts), state} 
    end 
    def handle_call(request, from, state), do: super(request, from, state) 
end 

Daha sonra koşu sürecini bir komut gönderebilir:

cevap

8

Sadece aşağıdaki gibi kurulmuş bir GenServer, kullanacağı

# If you want the result 
{contents, _} = Run.Command.run("cat", ["path/to/some/file"]) 
# If not, just ignore it 
Run.Command.run("cp", ["path/to/source", "path/to/destination"]) 

Temelde biz yaratıyoruz bir "singleton" işlemi (yalnızca bir işlem belirli bir adla kaydedilebilir ve biz de bu işlemin çalışması sırasında Run.Command işleminin modülün adıyla kaydedildiğinden, işlem devam ederken start_link'a yapılan herhangi bir ardışık çağrı başarısız olur. Bu, bir API oluşturmayı kolaylaştırır ( run işlevi), çağrı işleminin bu konuda herhangi bir şey bilmek zorunda kalmadan, diğer işlemde komutunu şeffaf olarak yürütebilir. Burada vs cast kullandım, ancak sonuca hiç dikkat etmeyecekseniz ve arama sürecinin engellenmesini istemiyorsanız önemsiz bir değişiklik olur.

Bu, uzun süre çalışan bir şey için daha iyi bir modeldir. Tek seferlik şeyler için Task çok daha basit ve kullanımı daha kolay, ama ben şahsen böyle global süreçler için GenServer kullanmayı tercih ediyorum.

+3

Bu mükemmel bir çözümdür. Bir Görev verememenin nedeni, mesaj göndermek istiyorsanız artık bir Görev kullanmak istemiyor olmanızdır. –

+0

Bunu ayrıntılı olarak açıkladığınız için teşekkür ederiz. Bu benim için @bitwalker için çok yararlı oldu. Zaman, yardım ve sabır için teşekkür ederim. – kkirsche

+0

@bitwalker Bunu kullanmaya çalışırken bir GenServer.call zaman aşımı alıyorum. Denetim odamı böyle bir şeyin olmasını engellememeli mi? (exit) çıkışı: GenServer.call (Run.Command, {: run, "ls", ["."]}, 5000) ** (EXIT) zaman aşımı (elixir) lib/gen_server.ex: 356 : GenServer.call/3 – kkirsche