Elixir 从_模块外部调用Genserver__

Elixir 从_模块外部调用Genserver__,elixir,phoenix-framework,gen-server,Elixir,Phoenix Framework,Gen Server,调用函数时,如果找不到预期的数据,我希望重试该函数。我想在函数失败后10秒后重试 目前的执行情况: 调度程序 发电机服务器: 如您所见,如果不满足case语句,我将尝试重试该函数。但这并不完全有效 输出: 它从不从服务器内部调用genserver。请重试。我是一个超级GenServer noob,所以请原谅我缺乏理解。谢谢 所以这里有一些地方需要改进 首先,您正试图通过注册名称进程访问您的GenServer。在服务器之后发送。\u。重试…,但不实际注册名称 注册名称的基本方法是在对GenServ

调用函数时,如果找不到预期的数据,我希望重试该函数。我想在函数失败后10秒后重试

目前的执行情况: 调度程序 发电机服务器: 如您所见,如果不满足case语句,我将尝试重试该函数。但这并不完全有效

输出:
它从不从服务器内部调用genserver。请重试。我是一个超级GenServer noob,所以请原谅我缺乏理解。谢谢

所以这里有一些地方需要改进

首先,您正试图通过注册名称进程访问您的GenServer。在服务器之后发送。\u。重试…,但不实际注册名称

注册名称的基本方法是在对GenServer.start_链接的调用中包含:name opt,例如:

接下来,从设计角度来看,您已经破坏了Retry GenServer的封装。作为一个快速的经验法则:

模块中使用的原子不需要被其他模块知道,除非它们是API(如OPT和结构)的明确部分

我们如何修复它?易于理解的将对Process.send_的调用置于服务器内部的/3之后。重试模块:

我发现这方面是学习GenServer最容易混淆的部分之一:本模块中定义的一些代码在GenServer进程中运行,而一些代码在其他进程中运行。具体地说,这两个API方法旨在由其他进程调用—由主管启动链接,由实际客户端重试

通过将Process.send\u after调用放在一个API方法中,我们简化了其他方法,并将重试服务器执行的操作与使用send\u after完成的操作解耦

我的最后一个建议是:要么让重试服务器更通用,要么更具体。现在,它只能帮助调度器,因为它太具体了——重试操作是硬编码的。一种方法是让retry接受一个arity-0函数,以便在重试时调用:

def retry(action, delay \\ 10_000) do
  Process.send_after(__MODULE__, {:retry, action}, delay)
end
# ...snip
def handle_info({:retry, action}, state) do
  action.()
  {:noreply, state}
end 

现在,它可以重试任何操作-只需向其传递lambda即可。另一方面,这似乎是一个可能无法评价抽象的特性。在本例中,只需将两个模块折叠为一个。我不能给你一个代码示例,因为我不确定Scheduler中还有什么,但是把它们混合在一起应该不会太麻烦。

所以这里有一些需要改进的地方

首先,您正试图通过注册名称进程访问您的GenServer。在服务器之后发送。\u。重试…,但不实际注册名称

注册名称的基本方法是在对GenServer.start_链接的调用中包含:name opt,例如:

接下来,从设计角度来看,您已经破坏了Retry GenServer的封装。作为一个快速的经验法则:

模块中使用的原子不需要被其他模块知道,除非它们是API(如OPT和结构)的明确部分

我们如何修复它?易于理解的将对Process.send_的调用置于服务器内部的/3之后。重试模块:

我发现这方面是学习GenServer最容易混淆的部分之一:本模块中定义的一些代码在GenServer进程中运行,而一些代码在其他进程中运行。具体地说,这两个API方法旨在由其他进程调用—由主管启动链接,由实际客户端重试

通过将Process.send\u after调用放在一个API方法中,我们简化了其他方法,并将重试服务器执行的操作与使用send\u after完成的操作解耦

我的最后一个建议是:要么让重试服务器更通用,要么更具体。现在,它只能帮助调度器,因为它太具体了——重试操作是硬编码的。一种方法是让retry接受一个arity-0函数,以便在重试时调用:

def retry(action, delay \\ 10_000) do
  Process.send_after(__MODULE__, {:retry, action}, delay)
end
# ...snip
def handle_info({:retry, action}, state) do
  action.()
  {:noreply, state}
end 
现在,它可以重试任何操作-只需向其传递lambda即可。另一方面,这似乎是一个可能无法评价抽象的特性。在本例中,只需将两个模块折叠为一个。我不能给你们一个代码示例,因为我不确定调度器中还有什么,但把它们混合在一起应该不会太麻烦

#Reference<0.1408720145.4224712705.56756>
def start_link(args) do
  GenServer.start_link(__MODULE__, args, [name: __MODULE__])
end
defmodule Servers.Retry do
  use GenServer

  ### External API:

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

  def retry(delay \\ 10_000) do
    Process.send_after(__MODULE__, :retry, delay)
  end

  ### GenServer Callbacks

  def init(state) do
    {:ok, state}
  end

  def handle_info(:retry, state) do
    Scheduler.check_question()
    {:noreply, state}
  end
end
def retry(action, delay \\ 10_000) do
  Process.send_after(__MODULE__, {:retry, action}, delay)
end
# ...snip
def handle_info({:retry, action}, state) do
  action.()
  {:noreply, state}
end