Elixir 在控制器内启动进程

Elixir 在控制器内启动进程,elixir,phoenix-framework,Elixir,Phoenix Framework,考虑这样的模块: 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 }] ) e

考虑这样的模块:

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 CopController中被实例化如下:

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处理程序。

原因

首先,控制器都是独立的进程。这意味着当用户发出请求时,进程启动,当他得到响应时,进程终止。 通过使用start_链接启动进程,可以创建一个双向链接,使死亡事件传播到其他链接的进程。也就是说,如果你有如下连接:

Cgas.Controller <----> Sample
Cgas.Controller示例
这意味着如果
Sample
Cgas.Controller
中的任何一个死亡,它们都将死亡。根据控制器如何工作的内部系统,这意味着
Sample
只要客户端连接到服务器(通常为1-100ms),它就会一直存在

这可能就是你注意到它“什么都不做”的原因,因为它生命中没有足够的时间(可怜的东西)

解决方案

您可以做的第一件事就是简单地用
start/2
而不是
start\u link/2
启动流程,但是它会为向服务器发出的每个请求创建一个流程,而这很可能最终成为一个僵尸流程大军

如果你真的坚持这样做,你可以给它一段时间去生活。类似于进程和进程的寄存器:
#如果客户端在X秒内没有发出任何新请求,就自杀
:erlang.exit self,:'die!'

但一般来说,这是对web框架的“火与忘”规则的挑战,最好使用像WebSockets这样的实时连接,并使过程与连接的寿命一样长

原因

首先,控制器都是独立的进程。这意味着当用户发出请求时,进程启动,当他得到响应时,进程终止。 通过使用start_链接启动进程,可以创建一个双向链接,使死亡事件传播到其他链接的进程。也就是说,如果你有如下连接:

Cgas.Controller <----> Sample
Cgas.Controller示例
这意味着如果
Sample
Cgas.Controller
中的任何一个死亡,它们都将死亡。根据控制器如何工作的内部系统,这意味着
Sample
只要客户端连接到服务器(通常为1-100ms),它就会一直存在

这可能就是你注意到它“什么都不做”的原因,因为它生命中没有足够的时间(可怜的东西)

解决方案

您可以做的第一件事就是简单地用
start/2
而不是
start\u link/2
启动流程,但是它会为向服务器发出的每个请求创建一个流程,而这很可能最终成为一个僵尸流程大军

如果你真的坚持这样做,你可以给它一段时间去生活。类似于进程和进程的寄存器:
#如果客户端在X秒内没有发出任何新请求,就自杀
:erlang.exit self,:'die!'


但一般来说,这是对web框架的“火与忘”规则的挑战,最好使用像WebSockets这样的实时连接,并使过程与连接的寿命一样长

start
具有相同的效果
start
具有相同的效果从repl调用哪个enter?如何验证进程是否处于活动状态?我通过
process.alive?
检查进程是否处于活动状态。我在repl中调用了它,并且
enter
works.Which enter。其中有两个是
enter
from sample,它启动进程。哪个enter是从repl调用的?如何验证进程是否处于活动状态?我通过
process.alive?
检查进程是否处于活动状态。我在repl中调用了它,并且
enter
works.Which enter。其中有两个
从示例中输入
,它启动了一个过程。