Elixir GenServer 投射和 start_link
Elixir GenServer cast and start_link
这是我使用 Elixir 的前 2 个小时,所以这可能是一个菜鸟问题,但我在生成 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
watcher 工作得很好,它接收新日志,但我遇到了使用 GenServer
的 Test.Receiver
的问题。
我的第一个问题是...我在哪里启动这个生成服务器? ExFSWatch
有它自己的 start
方法,我无法覆盖它。每次新日志传入时我都会调用 start_link
吗(我对此表示怀疑,但我不得不问)?
我读过的所有示例都应该从其他地方开始,抓住它 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
好的,为了扩展@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
如您所见,传递给主管调用的第二个参数是我要注册此模块的名称。这可能是我认为的任何你喜欢的东西,因为我对此不太确定。第二个参数进入我的接收器的 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 不同的抓取和传递信息作为参数和状态一直但是..我现在看到太阳了。
这是我使用 Elixir 的前 2 个小时,所以这可能是一个菜鸟问题,但我在生成 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
watcher 工作得很好,它接收新日志,但我遇到了使用 GenServer
的 Test.Receiver
的问题。
我的第一个问题是...我在哪里启动这个生成服务器? ExFSWatch
有它自己的 start
方法,我无法覆盖它。每次新日志传入时我都会调用 start_link
吗(我对此表示怀疑,但我不得不问)?
我读过的所有示例都应该从其他地方开始,抓住它 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
好的,为了扩展@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
如您所见,传递给主管调用的第二个参数是我要注册此模块的名称。这可能是我认为的任何你喜欢的东西,因为我对此不太确定。第二个参数进入我的接收器的 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 不同的抓取和传递信息作为参数和状态一直但是..我现在看到太阳了。