Elixir 使父进程保持活动状态
首先,我对长生不老药很陌生,所以这可能是一个误导性的问题 我有一个启动两个进程的函数 第一个进程使用erlang:fs库监视目录中的文件更改,然后向第二个进程发送消息 第二个进程等待目录中的文件已更改的消息,当它收到该消息时,运行一个函数重新生成HTML报告(这是一个发票) 看起来是这样的:Elixir 使父进程保持活动状态,elixir,Elixir,首先,我对长生不老药很陌生,所以这可能是一个误导性的问题 我有一个启动两个进程的函数 第一个进程使用erlang:fs库监视目录中的文件更改,然后向第二个进程发送消息 第二个进程等待目录中的文件已更改的消息,当它收到该消息时,运行一个函数重新生成HTML报告(这是一个发票) 看起来是这样的: def run_report_daemon(line_item_dir) do if Process.whereis(:html_daemon) == nil do spawn(HT
def run_report_daemon(line_item_dir) do
if Process.whereis(:html_daemon) == nil do
spawn(HTMLInvoiceDaemon, :run_daemon, [line_item_dir])
|> Process.register(:html_daemon)
end
if Process.whereis(:file_watcher) == nil do
:fs.start_link(:file_watcher, Path.absname(line_item_dir))
end
Process.sleep(1000)
run_report_daemon(line_item_dir)
end
这“有效”,但困扰我的是“睡眠”和递归调用
我的问题是:有没有更好的方法使包含生成我的进程的函数的进程保持活动状态。如果没有递归调用和睡眠,它就会死掉,并带走其他进程。由于递归调用和无睡眠,它会消耗大量处理器资源,因为它会快速循环
if块是必需的,因为否则它将重复生成和注册进程
我曾想过使用Supervisor,但我不确定如何在Supervisor下启动:fs流程,即使在这种情况下,我也需要保持启动流程的活力
我怀疑我的问题是因为对《长生不老药》中“正确做事方式”的根本误解
(注意:我可能不需要像这样的派生过程就可以完成整个过程,但这是一个学习练习)我可能会这样做 请注意,如果其中任何一个崩溃,主管将重新启动它,我们将以正确的状态结束,其中有一个
FSWatch
进程和一个InvoiceDaemon
进程,InvoiceDaemon
进程将侦听FSWatch
进程
策略是“rest”for_one,如果FSWatch
进程死亡,它将重新启动InvoiceDaemon
进程。这将防止InvoiceDaemon
进程订阅不再存在的FSWatch
。如果InvoiceDaemon
崩溃,则无需重新启动FSWatch
进程,因为当InvoiceDaemon
恢复时,它将重新订阅,然后永远运行
defmodule Thing do
use Supervisor
# Wraps the :fs.start_link
# thing in a process and goes to sleep
defmodule FSWatch do
def start_link(target_dir) do
watcher = spawn_link(fn ->
IO.puts "Watching #{target_dir}"
:fs.start_link(:file_watcher, target_dir)
:timer.sleep(:infinity)
end)
{:ok, watcher}
end
end
# Subscribe to the file watcher and then listen
# forever
defmodule InvoiceDaemon do
def start_link do
daemon = spawn_link(fn ->
:fs.subscribe(:file_watcher, "/path")
run()
end)
{:ok, daemon}
end
defp run do
receive do
{_, {:fs, file_event}, path} ->
IO.puts "Got a file event #{inspect path}"
run()
e ->
IO.puts "unexpected event #{inspect e}"
run()
end
end
end
def start_link do
target_dir = "/foo/bar"
children = [
worker(FSWatch, [target_dir]),
worker(InvoiceDaemon, [])
]
IO.inspect self
Supervisor.start_link(children, strategy: :rest_for_one)
end
end
Thing.start_link
:timer.sleep(:infinity)
如果您不打算使用supervisor,这是正确的方法,您可以为这些流程使用链接/监视器 您将链接/监视这些进程,而不是休眠/递归调用。然后,您等待一条停机消息,当他们中的任何一个死亡时,该消息会发送给您 好的方面是,您正在阻止接收,因此没有资源消耗 事实上,这是一个主管的基础,如果可能的话,我会推荐一个
有关更多信息,请参阅上的文档和函数。您将消息发送到
HTMLInvoiceDaemon
的确切位置?您可以发布更多的代码吗?包含一个函数,允许另一个进程订阅以接收来自:fs进程的消息。在HTMLInvoiceDaemon中,我订阅来自:file_watcher的消息,然后对这些消息执行操作。line_item_dir
是任意的还是您在开始时就知道这些?还有,他们有多少人?我曾试图回答,但后来意识到,如果应用程序启动时不知道输入,则很难获取输入。已知输入-从命令行作为选项传入的单个目录..我将提供更多您选择这种方式的示例。我不能,因为我现在在手机上。谢谢!这就是我昨晚提出的基本解决方案:在接收块等待并捕获退出消息,然后再进行递归调用。