gpt4 book ai didi

elixir - 在 Poolboy 工作线程 (gen_server) 中使用 System.cmd 会导致静默失败

转载 作者:行者123 更新时间:2023-12-02 21:11:08 26 4
gpt4 key购买 nike

我有一个由 poolboy 工作人员生成的函数

基本概述:

  • Phoenix Controller 使用数据调用 Dispatcher
  • 调度程序将数据传递给 Poolboy 工作线程
  • Poolboy 工作线程使用给定的数据生成一个新进程来处理
  • 新进程使用数据调用系统命令(在本例中为 wget)

我遇到的问题是,当我运行 ExUnit 测试时,它一直很好地到达生成的进程,并且我可以输出数据(使用 IO.inspect)。

当我运行 System.cmd("wget".... 当 ExUnit 测试运行时,我在终端中看到 wget 输出,因此该命令实际上正在运行,但在该命令之后我执行的任何操作都不会运行。

所以在我的 worker 中,如果我这样做:

IO.puts "hello"
System.cmd("wget", opts)
IO.puts "world"

然后我看到 hello 我看到了 wget 的输出,但没有看到 world

如果我做其他事情,例如:

IO.puts "hello"
File.write("/tmp/temp.txt", "test")
IO.puts "world"

然后我看到 helloworld 并且写入了一个文件。

是否有关于 System.cmd 的特定内容我遗漏了导致出现这种情况?当它不在单独的进程中运行时它可以正常工作,因此它是进程和 System.cmd 的组合。

有什么想法吗?谢谢!

最佳答案

您已进入 Elixir 标记的部分

“这里有龙”

System.cmd 只是 Port 的一个简单包装,而 Port 很大程度上是一个Erlang port 函数的未记录包装器。

http://www.erlang.org/doc/man/erlang.html#open_port-2

底层的 Erlang BEAM 进程调度程序是建立在以下假设之上的:可以在很短的时间间隔内“交换”进程。如果你只使用 Erlang/Exilir代码,它全部被设计为在 BEAM VM 中工作。任何可能阻塞或挂起系统调用的代码都需要在驱动程序中运行。这是一个特殊的Erlang VM 的接口(interface),将 Erlang 调度程序与任何可能挂起系统调用的进程隔离开来。

Ports 驱动程序被设置为处理对外部程序的调用。

System.cmd最终调用

 do_cmd Port.open({:spawn_executable, cmd}, opts), initial, fun

端口在单独的进程中运行,do_cmd 例程运行接收循环直到它收到来自底层 Erlang 端口的退出状态。所以System.cmd 将“阻止”该特定 BEAM 进程,直到 wget unix进程退出。

但是,Elixir BEAM 的其余流程将会顺利进行。我对 PoolBoy 不太熟悉,不知道是否有某种超时对您的工作人员进行监控或心跳。但是,如果有并且 wget 命令超过此超时,工作进程可能会在 wget 命令之前退出完成。

System.cmd 并未真正设置为处理可能需要很长时间的命令周围的所有问题。我建议您研究一下 Porcelain 模块,将其作为 Erlang 端口相当复杂的主题的一个很好的包装器。

https://github.com/alco/porcelain

或者,由于您正在执行一个简单的 wget,因此使用 Elixir 或 Erlang HTTP 客户端模块可能会在 BEAM 框架中工作得更好。

关于elixir - 在 Poolboy 工作线程 (gen_server) 中使用 System.cmd 会导致静默失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30907228/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com