考虑这样的模块:
defmodule Sampple do
def start(nick, password, state \\ %State{}) do
{:ok, client} = ExIrc.start_client!
GenServer.start(__MODULE__,
[%{state | client: client,
nick: nick,
pass: password
}]
)
end
def enter(nick, token) do
Logger.debug "Sending message"
start(nick, token)
end
#another irrelevant callbacks
def handle_info({:joined, _}, state) do
ExIrc.Client.msg(state.client,
:privmsg,
state.channel,
"!enter")
{:stop, :normal, state}
end
end
这样的GenServer在Phoenix Copntroller中实例化如下:
defmodule Cgas.Controller do
use Cgas.Web, :controller
require Logger
def enter(conn, _args) do
Logger.debug inspect(get_session(conn, :login))
%{"login" => login,
"token" => token } = get_session(conn, :login)
{:ok, pid} = Sample.enter(login, token)
Logger.debug inspect(pid)
json conn, %{"success" => "true "}
end
end
如果从repl或非控制器进程调用enter
,则没有问题,尽管从控制器内部调用它时,进程仍处于活动状态但不执行任何操作。此示例模块用作ExIRC处理程序。
答案 0 :(得分:0)
<强>原因强>
首先,所有控制器都是独立的过程。这意味着当用户发出请求时,流程开始,当他收到响应时,流程就会消失。 通过使用start_link启动进程,您可以创建一个双向链接,使死亡事件传播到其他链接进程。这意味着如果你有这样的连接:
Cgas.Controller <----> Sample
这意味着,如果Sample
或Cgas.Controller
死亡,则两者都会死亡。根据控制器如何工作的内部系统,它意味着Sample
只要客户端连接到服务器就会存在(通常为1-100毫秒)
这可能是你注意到它&#34;没有做任何事情的原因&#34;因为它的生命中没有足够的时间(可怜的东西)
<强>解决方案强>
您可以做的第一件事就是使用start/2
而不是start_link/2
启动流程。但是,它会为每个向服务器发出的请求创建一个流程,最有可能最终成为一群僵尸进程。
如果你真的坚持这样做,那么你可以给它一个时间来生活。像过程注册的东西和:
# if client didn't make any new request in X seconds commit suicide
:erlang.exit self, :'die!'
但通常情况下,它再次成为网络框架的火花和遗忘规则,并且使用像WebSockets这样的实时连接要好得多,并且只要连接存在就让流程生效。