我一直在学习elixir只有几个星期了,我想用它的应用程序模块,主管和(目前只有一个)工人设置一个合适的应用程序。
通过教程,文档,Elixir论坛和stackoverflow的日子让我了解了这一点:
use Application
Supervisor.start_link/2
并存储返回的pid足以用于简单的应用程序。start/2
函数返回{:ok, pid}
(这是其中最后一次调用的返回值,Supervisor.start_link(worker_module, options)
)child_spec/2
,init/1
和start_link/1
Supervisor.start_link/2
在具有给定选项的工作人员上调用init/1
然后调用start_link/1
init/1
返回特定值现在,我的最后一部分有问题。根据我得到的错误,我的工作人员的init
函数返回“错误值”,但我无法弄清楚应该是supervisor.start_link/2
的返回值不是失败。
当init被定义为init(opts)
:
这是我在第{:ok, pid} = Supervisor.start_link(MyAppMain.Worker, [])
行之后从记录器获得的错误消息:
** (Mix) Could not start application myapp: exited in: MyAppMain.start(:normal, [])
** (EXIT) an exception was raised:
** (MatchError) no match of right hand side value: {:error, {:bad_return, {MyAppMain.Worker, :init, {:ok, %{}}}}}
lib/MyAppMain.ex:15: MyAppMain.start/2
(kernel) application_master.erl:273: :application_master.start_it_old/4
那么,Supervisor.start_link/2
接受的返回值是什么?
编辑:一些实际代码
申请模块:
defmodule MyAppMain do
use Application
def start(_type, _args) do
{:ok, pid} = Supervisor.start_link(MyAppMain.Worker, [])
end
end
工人模块:
defmodule MyAppMain.Worker do
def child_spec(opts) do
%{
id: MyAppMain.Worker,
start: {__MODULE__, :start_link, []},
restart: :transient,
type: :worker
}
end
def start_link(state) do
do_work() # returns a "fn() -> nil end", because "expected a function"
end
def init(opts) do
{:ok, %{}} # Also tried putting the elements of the above list here.
end
defp do_work()
#do some work
if(prompt_restart()) do
do_work()
else
fn() -> nil end
end
end
defp prompt_restart() do
# prompt the user whether to repeat the task via IO.gets, return either true or false
end
end
答案 0 :(得分:3)
问题在于您设置应用程序的方式。您将应用程序视为主管(有点像,但不像您正在使用它),并且您的工作程序的start_link部分使用错误。该应用程序实际上只是用于启动一些顶级主管,他们自己启动一些工作人员。这是一个基本的例子:
应用:
defmodule Chat do
use Application
def start(_type, _args) do
Chat.Supervisor.start_link(name: Chat.Supervisor)
end
end
主管(由应用程序启动)
defmodule Chat.Supervisor do
def start_link(state) do
Supervisor.start_link(__MODULE__, nil, named: __MODULE__)
end
def init(opts) do
children = [
%{
id: Chat.RoomWorker,
start: {Chat.RoomWorker, :start_link, []},
restart: :transient,
type: :worker
}
]
Supervisor.init(children, strategy: :one_for_one)
end
end
工人(由主管发起)
defmodule Chat.RoomWorker do
use GenServer
def start_link() do
GenServer.start_link(__MODULE__, nil, named: __MODULE__)
end
def init(opts) do
{:ok, []}
end
end
start_link
调用成功后返回{:ok, pid}
。 init
函数在生成的进程中发生,它返回一些{:ok, state}
响应,让spawner知道它已成功启动。 start_link
内容在调用者进程中运行,init
代码在新生成的进程中运行。
尝试重构代码,以便应用程序启动顶级主管,并且该主管正在启动一些工作进程。虽然您可以从应用程序启动工作人员并放弃主管,但最好放弃应用程序并仅使用主管,但最好还是看看所有3个如何协同工作。