2015-07-14 16 views
7

Tôi thực sự đang đấu tranh với các giám sát viên Elixir và tìm cách đặt tên cho họ để tôi có thể sử dụng chúng. Về cơ bản, tôi chỉ đang cố gắng bắt đầu một số Task được giám sát mà tôi có thể gửi tin nhắn đến.Giám sát viên Elixir - Làm thế nào để bạn đặt tên một Nhiệm vụ được Giám sát

Vì vậy, tôi có như sau:

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

với điểm vào dự án như:

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 

Tại thời điểm này, tôi thậm chí không cảm thấy tự tin rằng mình đang sử dụng là điều đúng đắn (Task cụ thể). Về cơ bản, tất cả những gì tôi muốn là để sinh ra một quá trình hoặc nhiệm vụ hoặc GenServer hoặc bất cứ điều gì là đúng khi ứng dụng bắt đầu mà tôi có thể gửi các thông điệp mà về bản chất sẽ làm một System.cmd(cmd, opts). Tôi muốn nhiệm vụ hoặc quy trình này được giám sát. Khi tôi gửi một tin nhắn {:run, cmd, opts} như {:run, "mv", ["/file/to/move", "/move/to/here"]} Tôi muốn nó sinh ra một nhiệm vụ hoặc quy trình mới để thực hiện lệnh đó. Để sử dụng, tôi thậm chí không cần lấy lại phản hồi từ nhiệm vụ, tôi chỉ cần nó thực hiện. Bất kỳ hướng dẫn về nơi để đi sẽ là hữu ích. Tôi đã đọc qua hướng dẫn bắt đầu nhưng thực sự nó khiến tôi bối rối hơn bởi vì khi tôi cố gắng làm những gì được thực hiện nó không bao giờ quay ra như trong ứng dụng.

Cảm ơn sự kiên nhẫn của bạn.

Trả lời

8

tôi sẽ chỉ sử dụng một GenServer, thiết lập như sau:

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 

Sau đó bạn có thể gửi các tiến trình đang chạy một lệnh để thực hiện như sau:

# 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"]) 

Về cơ bản chúng tôi đang tạo quy trình "singleton" (chỉ một quy trình có thể được đăng ký với tên đã cho) và chúng tôi đang đăng ký quy trình Run.Command với tên của mô-đun, vì vậy bất kỳ lệnh gọi nào liên tiếp đến start_link trong khi quá trình đang chạy sẽ không thành công. điều này giúp dễ dàng thiết lập API () Chức năng) có thể thực hiện lệnh trong suốt trong quá trình khác mà không cần quá trình gọi điện thoại phải biết bất kỳ điều gì về nó. Tôi đã sử dụng call so với cast ở đây, nhưng đó là một thay đổi nhỏ nếu bạn không bao giờ quan tâm đến kết quả và không muốn quá trình gọi điện thoại chặn.

Đây là mô hình tốt hơn cho một thứ dài hạn. Đối với những thứ một lần, Task đơn giản hơn nhiều và dễ sử dụng hơn, nhưng tôi thích sử dụng GenServer cho các quy trình toàn cầu như thế này.

+3

Đó là giải pháp hoàn hảo. Lý do tại sao bạn không thể đặt tên cho Task là vì nếu bạn muốn gửi tin nhắn ... bạn không muốn sử dụng Task nữa. –

+0

Cảm ơn bạn đã giải thích chi tiết này. Điều này rất hữu ích cho tôi @bitwalker. Cảm ơn bạn đã dành thời gian, hỗ trợ và kiên nhẫn. – kkirsche

+0

@bitwalker Khi cố gắng sử dụng điều này, tôi nhận được một thời gian chờ GenServer.call. Không nên người giám sát ngăn chặn loại điều này xảy ra? (thoát) đã thoát trong: GenServer.call (Chạy.Command, {: run, "ls", ["."]}, 5000) ** (EXIT) hết giờ (elixir) lib/gen_server.ex: 356 : GenServer.call/3 – kkirsche

Các vấn đề liên quan