gpt4 book ai didi

elixir - 在 Phoenix 中使用 GenServer - 进程不存在

转载 作者:行者123 更新时间:2023-12-04 01:58:39 26 4
gpt4 key购买 nike

我正在尝试使用 GenServer在 Phoenix 中将从不同客户端接收到的信息累积到 Web 套接字。 GenServer看起来像这样:

 defmodule HelloWeb.Stack do
use GenServer

@name {:global, __MODULE__} # this seems to help me to prevent having to drag the pid everywhere in the application

# Client
def start_link do
#GenServer.start_link(__MODULE__, [])
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end

def add(item) do
GenServer.cast(@name, item)
end

def view do
GenServer.call(@name, :view)
end

def remove(item) do
GenServer.cast(@name, {:remove, item})
end

def wipe do
GenServer.cast(@name, :wipe)
end

#Server
def init(list) do
{:ok, list}
end

def handle_cast(:wipe, _list) do
updated_list = []
{:noreply, updated_list}
end

def handle_cast({:remove, item}, list) do
updated_list = Enum.reject(list, fn(i) -> i == item end)
{:noreply, updated_list}
end

def handle_cast(item, list) do
updated_list = [item|list]
{:noreply, updated_list}
end

def handle_call(:view, _from, list) do
{:reply, list, list}
end
end

这是我的 Phoenix channel 的相关部分:
def handle_in("answer", payload, socket) do
HelloWeb.Stack.add(payload)
{:noreply, socket}
end

def handle_in("answers", _payload, socket) do
{:reply, {:ok, HelloWeb.Stack.view}, socket}
end

奇怪的是 "answer"每次我打电话时似乎都有效,但是 "answers"总是使 GenServer 崩溃:
[error] GenServer #PID<0.10032.0> terminating
** (stop) exited in: GenServer.call({:global, HelloWeb.Stack}, :view, 5000)
** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started

我不确定如何在多个 channel 操作之间共享一个 GenServer。如果我使用 iex所有的功能都完全按照我的预期工作,但在 Phoenix 中,初始化和使用是分散的。

我尝试在应用程序中启动 GenServer,如下所示:
defmodule Hello.Application do
use Application

# See https://hexdocs.pm/elixir/Application.html
# for more information on OTP Applications
def start(_type, _args) do
import Supervisor.Spec

# Define workers and child supervisors to be supervised
children = [
# Start the endpoint when the application starts
supervisor(HelloWeb.Endpoint, []),
# Start your own worker by calling: Hello.Worker.start_link(arg1, arg2, arg3)
worker(HelloWeb.Stack, []),
]

# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: Hello.Supervisor]
Supervisor.start_link(children, opts)
end

可悲的是,我在调试系统时遇到了麻烦,我还不知道如何正确地做到这一点。一次吸收很多新东西,而我距离 Elixir 启蒙还有一些距离。我添加了两个 debug端点以非常粗略的方式调试事物:
def handle_in("debug2", _payload, socket) do
{:reply, {:ok, %{ genserver: GenServer.whereis(HelloWeb.Stack) }}, socket}
end

def handle_in("debug1", _payload, socket) do
{:ok, pid} = HelloWeb.Stack.start_link
{:reply, {:ok, %{ genserver: GenServer.whereis(HelloWeb.Stack), pid: :erlang.pid_to_list(pid) }}, socket}
end
debug2只是不断返回 null对于 HelloWeb.Stack ,但是当我运行 debug1第一次收到 null和有效的 pid ,第二次崩溃时:
** (MatchError) no match of right hand side value: {:error, {:already_started, #PID<0.12310.0>}}
这似乎表明它成功启动,将自身绑定(bind)到一个唯一值,并且第二次这样做被拒绝,因为该特定进程已经启动。但是我不能使用 HelloWeb.Stack到达它。在进行一些更改和测试后,让我展示代码的其他相关部分:
defmodule HelloWeb.Stack do
use GenServer

@name {:global, __MODULE__}

# Client
def start_link do
#GenServer.start_link(__MODULE__, [])
GenServer.start_link(__MODULE__, [], name: @name)
end

这是在 application.ex 中启动 worker 的方式:
worker(HelloWeb.Stack, []), #how to verify it's really starting something and to what value it stores it's pid?

最佳答案

听起来您没有使用应用程序启动 GenServer,因此消息是正确的 - 例如没有进程活着。

原因HelloWeb.Stack.add(payload)功能仍然有效是因为这是 GenServer 的强制转换功能的意图,例如你投到这个过程,因为你不关心返回的结果,以及它是成功还是失败(否则你会使用 call )

例如:

iex(1)> GenServer.cast(:non_existing_genserver, :add)
:ok

在这里你可以看到即使 GenServer 不存在, cast仍然返回一个确认消息,但实际上它不会去任何地方。

要解决您的问题,请导航至您的 application.ex文件并添加一个工作程序以在应用程序启动时启动 GenServer。
children = [
#...other workers/supervisors
{HelloWeb, []}
]

关于elixir - 在 Phoenix 中使用 GenServer - 进程不存在,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48876826/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com