Elixir:应用程序立即退出,或者在运行 distillery 包时没有收到输入。为啥它会以这种方式工作,以及如何解决它?
Posted
技术标签:
【中文标题】Elixir:应用程序立即退出,或者在运行 distillery 包时没有收到输入。为啥它会以这种方式工作,以及如何解决它?【英文标题】:Elixir: application quits immediately, or doesn't receive input when running distillery package. Why does it work that way, and how to work around it?Elixir:应用程序立即退出,或者在运行 distillery 包时没有收到输入。为什么它会以这种方式工作,以及如何解决它? 【发布时间】:2018-05-17 08:57:10 【问题描述】:我有一个 Elixir 应用程序,其结构如下:
Application --> Supervisor --> Worker
应用程序模块相当简单,它有一个use Application
和一个
def start(_type, _args)
MyApp.Supervisor.start_link()
end
主管有点复杂:
def start_link() do
:ok, pid = Supervisor.start_link(__MODULE__, [], name: __MODULE__)
halt_exit(wait_for_child())
:ok, pid
end
def init(data) do
children =
[
worker(MyApp.Worker, [], restart: :transient)
]
Supervisor.init(children, [strategy: :one_for_one])
end
halt_exit(pid)
执行 Process.sleep(100)
并在每次发现进程 pid 仍处于活动状态时调用自身(或在 pid 不再活动时简单地返回 nil),wait_for_child
找到 Worker 模块的 pid(取考虑到它可能必须等到它启动)。
我的 Worker 模块使用 IO.puts
和 IO.gets
与用户交互。为什么所有这些复杂的不必要的逻辑?看来
myapp.bat console
并省略停止退出时,我的应用程序启动,立即终止,然后 iex 启动
当使用带有myapp.bat console
的混合版本并包含停止退出时,我的应用程序输出正确,但无法接收任何输入(我的意思是我无法在 werl.exe 的窗口中输入)李>
当使用带有myapp.bat foreground
的混合版本时,我的应用程序启动并且只有那时批处理文件中出现错误(系统找不到文件`%get_pid_cmd%`。
错误:无法识别搜索过滤器。
'@call' 未被识别为内部或外部命令,
可运行的程序或批处理文件。)此时我的应用程序终止。
当使用 mix run --no-halt(应用程序内没有退出暂停逻辑)时,我的应用程序会立即启动、终止,并且 erlang 虚拟机仍然在 cmd 窗口中运行
只有当我混合运行并包含 halt_exit/1
时,我的应用才能按预期工作
从这一切中,我得出的结论是 1) 当我的应用程序模块的 start/2
返回时,应用程序被关闭,这没有多大意义,因为 Elixir 是 设计的 用于将负载置于其他进程而不是,而不是除了应用程序的主模块的应用程序。 2)输入是通过主应用程序模块的进程完成的(但由于某种原因,仅在单独的 werl.exe 窗口中运行时,似乎可以正常运行混合运行),所以我不能放置任何阻塞直到工作完成如果我想要我的用户输入,逻辑就在那里。
我该如何解决这个问题,同样重要的是(这样我可以避免将来出现问题)是什么行为导致了我的问题?我需要能够在没有安装 mix 和 Erlang VM 的计算机上运行它,所以我唯一的选择是让它与生成的 distillery 包一起工作,目前我不能。
没有多少谷歌搜索导致我采用类似的策略来人为停止退出,而且我发现没有论坛/教程提到这种“提前退出”的问题,所以我想解决这个问题的正确方法是以某种方式得到它不想在任何进程运行时退出。
【问题讨论】:
我认为这与erlang中的group_leader
系统有关。 (***.com/a/36410816/1650580)
【参考方案1】:
系统找不到文件
%get_pid_cmd%
。错误:无法识别搜索过滤器
在下面一行:
@for /f "delims=" %%i in (`%%get_pid_cmd%%`) do set pid=%%i
尝试将%%get_pid_cmd%%
周围的反引号更改为单引号。
另外,在以下行中:
set get_pid_cmd=%escript% %nodetool% eval %node_type% %node_name% -setcookie "!cookie!" "erlang:list_to_integer(os:getpid()).'
将最后的单引号改为双引号。
来源:https://www.bountysource.com/issues/50408118-starting-in-foreground-mode-on-windows-fails-to-get-pid-and-returns-errorlevel-1
在 boot_win.eex 中进行这两项更改、删除 _build 文件夹和重建对我有用。
【讨论】:
以上是关于Elixir:应用程序立即退出,或者在运行 distillery 包时没有收到输入。为啥它会以这种方式工作,以及如何解决它?的主要内容,如果未能解决你的问题,请参考以下文章