【问题标题】:Calling a GenServer fails due to an incorrect name由于名称不正确,调用 GenServer 失败
【发布时间】:2021-05-07 10:38:11
【问题描述】:

我在图书馆中有这个 GenServer:

defmodule MyLib.Cache do
  use GenServer

  def start_link([]) do

    IO.puts("****cache genserver, name: #{__MODULE__}")


    # GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
    GenServer.start_link(__MODULE__, %{}, name: MyLibCache)   # no dot
  end
  # [.........]

还有这个应用程序:

    defmodule MyApp.Application do
      use Application

      def start(_type, _args) do
        import Supervisor.Spec

        children = [
          {Phoenix.PubSub, [name: MyApp.PubSub, adapter: Phoenix.PubSub.PG2]},
          {MyLib.Repo, []},
          {MyAppWeb.Endpoint, []},
          {MyLib.Cache, []} # notice the dot
        ]
  • 为什么当我指定名称时它可以工作:MyLibCache(不带点)虽然名称必须是 MyLib.Cache - 带点?

  • 我希望能够在 GenServer 中使用name: __MODULE__。但是有了它,它将无法在application.ex 中启动它,因为它不会找到具有这样名称的模块。如何解决?

更新

运行时出错,当我尝试访问调用缓存的页面时,即不在启动时:

exited in: GenServer.call(MyLibCache, {:get, "Elixir.MyLib.Dal.User.2"}, 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

也就是说,这将不会出错:

GenServer.start_link(__MODULE__, %{}, name: MyLibCache)
# or 
# GenServer.start_link(__MODULE__, %{}, name: MyLib.Cache) # with dot

this - 上面显示的错误:

GenServer.start_link(__MODULE__, %{}, name: __MODULE__)

【问题讨论】:

    标签: elixir gen-server


    【解决方案1】:

    Supervisor.Spec 自 Elixir 1.5 起已被弃用。您不需要使用它。这是一个工作示例:

    defmodule MyLib.Cache do
      use GenServer
    
      def init(state), do: {:ok, state}
    
      def start_link(state) do
        GenServer.start_link(__MODULE__, state, name: __MODULE__)
      end
    end
    

    然后在application.ex:

    def start(_type, _args) do
      children = [
        MyLib.Cache
      ]
    
      opts = [strategy: :one_for_one, name: MyApp.Supervisor]
      Supervisor.start_link(children, opts)
    end
    

    为什么当我指定名称时它可以工作:MyLibCache(不带点)虽然名称必须是 MyLib.Cache - 带点?

    GenServer.start_link/3name 参数是服务器 的名称,而不是模块的名称。它们可以相同,但不必相同。您在此处提供的名称是稍后需要提供给Genserver.call/3 的名称。详情请见Name registration

    【讨论】:

    • __MODULE__ in defmodule MyLib.Cache 将评估为 Elixir.MyLib.Cache,而在 application.ex 中您将其简称为 MyLib.Cache。它是如何工作的?
    • 在 Elixir 中,模块名称只是原子。它们都以Elixir. 开头,但为简洁起见省略。你可以通过IO.puts(MyLib.Cache) 来测试它。还有is_atom(MyLib.Cache)Elixir.MyLib.Cache == MyLib.Cache
    猜你喜欢
    • 2019-09-30
    • 1970-01-01
    • 2018-05-18
    • 2015-01-18
    • 2021-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多