【问题标题】:GenServer call inside macro宏内的 GenServer 调用
【发布时间】:2016-11-05 17:17:37
【问题描述】:

我定义了一个这样的宏:

defmodule Test do
  defmacro __using__ do
    quote do
      require Test
      import Test
    end
  end

  defmacro my_macro do
    quote do
      Gernserver.call() # generic server call from other module
    end
  end
end

我在正在构建的库中有这段代码。在其他应用程序中测试此库时,我在包含 use Test 的文件上收到编译错误。

错误:exited in: GenServer.call ...exit no process(在 my_macro 调用的行上,更具体地说在 genserver 调用上)。好像genserver没有运行,不是因为是编译时间。

using 宏添加一个简单的 Application.ensure_all_started(:lib_name) 似乎可以解决问题。但是话又说回来,在编译时代码不应该运行,对吗?或者这里是我没有看到的东西?也许我不能在宏上使用 genserver 调用?

谢谢。

【问题讨论】:

标签: macros elixir


【解决方案1】:

您在编译阶段在您的TestScheduler 中调用every

应该将所有调度初始化代码放在一个函数中,该函数将在运行阶段显式调用,或者简单地 引入一个新的GenServer,将其添加到监督列表(以使 Elixir 在应用程序启动时自动运行它)并在其 start_link 中执行此 every 初始化(或稍后将显式调用的任何其他函数):

defmodule Test.Scheduler do
  use GenServer
  use Cronex.Scheduler

  def start_link ... do
    every :minute do
      IO.puts "every minute job"
    end

    every :minute do
      IO.puts "every minute job 2"
    end
  end
end

另一种方法(如果您想保持上面的文件尽可能干净)是every 宏中收集数据,然后产生所有调用 em> 在运行阶段。


为了更加熟悉阶段,请将以下代码放入/tmp/test.ex

defmodule A do
  IO.puts "Here “every” macro was called: compilation"

  def a do
    IO.puts "Is not called during compilation stage"
  end
end
IO.puts "=== compilation finished ==="
A.a

并发出elixir /tmp/test.ex

Here “every” macro was called: compilation
=== compilation finished ===
Is not called during compilation stage

【讨论】:

  • 这正是问题所在,感谢您的解释!
  • 我想我没有完全理解编译阶段是如何工作的。一切都在编译阶段运行,除了 def 调用中的代码我是对的吗?
  • 欢迎。无论您来自 ruby​​,您都可能发现相似之处:顶层的所有内容(例如类声明中的 DSL)都在解析阶段执行,而函数只是编译。 def blah do IO.puts end是编译的,而IO.puts是直接执行的(其实也是在编译的,只是编译的结果就是执行)希望只是没有让一切变得更纠结。跨度>
  • 完全没有,你再次让我明白了一切,再次感谢。
  • def 也是 Elixir 中的一个宏,它正在编译阶段执行def执行的结果是“准备好的代码”(AST)。不妨写在顶层@fun fn -> IO.puts end,编译成@fun准备好执行.
猜你喜欢
  • 2019-05-08
  • 2021-03-03
  • 2018-07-08
  • 2015-09-26
  • 2016-08-27
  • 2018-01-13
  • 1970-01-01
  • 2019-02-17
  • 1970-01-01
相关资源
最近更新 更多