Elixir GenServer cast和start_link

时间:2016-10-09 05:15:42

标签: elixir otp gen-server

这是我前两个小时的Elixir,所以这可能是一个愚蠢的问题,但我有一些产生GenServer并投下它的问题。我正在使用这个模块来监视系统中文件的变化,并且每次在该文件中添加新条目时,我想将日志转换为gen服务器,该服务器对其进行分析并执行基于应该做的任何事情。关于它的发现。

这是观察变化的模块:

defmodule Test.Watcher do
    use ExFSWatch, dirs: ["/var/log/"]

    import Test.Receiver, only: [analyze_log: 2]

    def callback(file_path, actions) do
        if file_path == "/var/log/syslog" do
            if :modified in actions do
                #~~~~ WHERE DO I GET THIS pid FROM?
                analyze_log pid, get_log
            end
        end
    end

    def get_log do
        {log, _} = System.cmd("tail", ["-n", "1", "/var/log/syslog"])
        log
    end
end

观察者工作得非常好并且收到新日志,但我遇到Test.Receiver使用GenServer的问题。

我的第一个问题是......我从哪里开始这台服务器? ExFSWatch拥有自己的start方法,我无法覆盖它。每次新日志传入时我都会调用start_link(我怀疑但我不得不问)?

Ny我读过的所有例子我都应该在其他地方启动它,抓住它pid并将它作为参数传递给analyze_log方法,所以,如果我是对的,我唯一的剩下的问题是找到一个好地方启动Test.Receiver Genserver并抓住它的pid所以我可以在callback方法中使用它。

defmodule Test.Receiver do
    use GenServer

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

    def analyze_log(pid, log) do
        GenServer.cast(pid, {:analyze_log, log})
    end

    def init(:ok) do
        {:ok, %{}}
    end

    def handle_cast({:analyze_log, log}, state) do
        IO.puts log
        {:noreply, state}
    end
end

1 个答案:

答案 0 :(得分:0)

好的,要扩展@ Dogbert的答案,并为其他以Elixir开头的人清除它,我会提供适合我的解决方案。它可能不是最优雅的,因为我还缺乏知识但却有效。

正如Dogbert所说,您需要为您的GenServer注册一个名称,并使用该名称进行调用。所以我去了我的主文件,并产生了一个主管,让这些听众保持活跃,如下所示:

defmodule Test do
    use Application

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

        Fail2ban.Watcher.start

        children = [
            # ... I have more here but let's keep it simple
            supervisor(Test.Receiver, [Test.Receiver]),
        ]

        opts = [strategy: :one_for_one, name: Test.Supervisor]
        Supervisor.start_link(children, opts)
    end
end

如您所见,传递给supervisor调用的第二个参数是我想要注册此模块的名称。它可能是我喜欢的任何东西,因为我不太确定。第二个参数进入我的接收者start_link并以该名称注册:

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

有了这个,现在记住接收器上的这个方法,我有关于pid的问题,我不知道从哪里得到:

defmodule Test.Watcher do
    use ExFSWatch, dirs: ["/var/log/"]

    import Test.Receiver, only: [analyze_log: 2]

    def callback(file_path, actions) do
        if file_path == "/var/log/syslog" do
            if :modified in actions do
                # Instead of the pid, pass the name under which it was registered
                analyze_log Test.Receiver, get_log
            end
        end
    end

    def get_log do
        {log, _} = System.cmd("tail", ["-n", "1", "/var/log/syslog"])
        log
    end
end

适合我,愿意讨论和改进。现在是Elixir的第二天,我开始掌握它的方法。来自Python,Ruby,PHP本身它有点 hard 不同的抓取和传递信息作为参数和状态所有时间但是......我现在看到了太阳。