在Poolboy worker(gen_server)中使用System.cmd会导致静默失败

时间:2015-06-18 05:36:38

标签: elixir phoenix-framework

我有一个由poolboy worker产生的功能

基本概述:

  • Phoenix Controller使用数据调用Dispatcher
  • Dispatcher将数据传递给Poolboy worker
  • Poolboy worker使用要处理的给定数据生成新进程
  • 新进程使用数据调用系统命令(本例中为wget)

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

当我运行System.cmd时(" wget" ....当ExUnit测试运行时,我看到终端中的wget输出,所以命令实际上正在运行,但随后我做了什么在那个命令没有运行之后。

所以在我的工作人员中,如果我这样做:

Product Serial #

然后我看到IO.puts "hello" System.cmd("wget", opts) IO.puts "world" 我看到了wget的输出,但我看不到hello

如果我做其他事情:

world

然后我看到IO.puts "hello" File.write("/tmp/temp.txt", "test") IO.puts "world" hello,并且写了一个文件。

我是否遗漏了导致此情况发生的world具体内容?它不能在单独的进程中运行时工作正常,因此它是进程和System.cmd的组合。

有什么想法吗?谢谢!

2 个答案:

答案 0 :(得分:5)

您已输入标记为Elixir的部分

"这里是龙"

System.cmd只是Port的一个简单包装,Port主要是。port Erlang System.cmd函数的未记录的包装器。

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

底层的Erlang BEAM进程调度程序是基于它的假设而构建的 可以"交换"以非常短的时间间隔进行处理。如果你只使用Erlang / Exilir 代码,它都被设计为在BEAM VM中工作。任何可能阻止或挂起系统调用的代码都需要在驱动程序中运行。这是一个特殊的 连接到Erlang VM,将Erlang调度程序与可以挂起系统调用的任何进程隔离开来。

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

do_cmd Port.open({:spawn_executable, cmd}, opts), initial, fun 最终调用

do_cmd

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

然而,其余的Elixir BEAM流程将以他们的快乐方式进行。 我对PoolBoy不太熟悉,知道是否存在某种超时 对你的工人进行监控或心跳。但是,如果有和wget命令 超过此超时,工作进程可能会在wget命令之前退出 完成。

Porcelain并未真正设置为处理可能需要很长时间的命令的所有问题。我建议您查看grep(c(pattern1, pattern2, pattern3), ...) 模块,作为围绕Erlang端口相当复杂的主题的一个很好的包装器。

https://github.com/alco/porcelain

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

答案 1 :(得分:0)

我遇到了同样的问题,并且能够通过使用-q选项运行wget命令来回避它。

System.cmd("wget", ["-q", url])

这似乎可以通过静音wget的输出来阻止进程卡住。