产生监督过程以定期报告心跳

时间:2016-07-22 10:00:08

标签: elixir supervisor

我正在尝试生成一个进程,该进程将每五秒发布一次HTTP请求,以向服务器报告其心跳。我的代码是:

defmodule MyModule.Heartbeat do
  def start_link do
    spawn_link(fn ->
      :timer.apply_interval(:timer.seconds(5), __MODULE__, :beat, [])
    end)
  end

  defp beat do
    HTTPoison.post "https://myserver/heartbeat
  end
end

defmodule MyModule.Supervisor do
  use Supervisor

  def start_link do
    Supervisor.start_link(__MODULE__, :ok)
  end

  def init(:ok) do
     children = [
       worker(MyModule.Heartbeat, [])
     ]

    supervise(children, strategy: :one_for_one)
  end
end

然而,当我尝试启动应用程序时,它会退出并显示以下错误:

[info] Application my_module exited: MyModule.start(:normal, []) returned an error: shutdown: failed to start child: MyModule.Heartbeat
    ** (EXIT) #PID<0.535.0>

我需要的只是一些进程,它将作为监督树的一部分运行,并在指定的时间间隔内发送它的请求。它不需要能够自己接收任何消息,我也不会对特定的实现感到困扰。

任何人都可以建议我在这里做错了什么阻止了这个过程的启动,以及是否有更好的方法来实现这个目标?

1 个答案:

答案 0 :(得分:1)

您的代码中有3个错误:

  1. :timer.apply_interval/4立即返回,因此匿名 传递给spawn_linkMyModule.Heartbeat.start_link/0的函数终止 执行该行后不久,导致:timer删除间隔 它的队列,而不是永远调用MyModule.Heartbeat.beat/0

    您可以通过添加:timer.sleep(:infinity)作为最后一个来解决此问题 表达式,使你的过程永远睡眠。

  2. MyModule.Heartbeat.beat/0需要是一个公共函数才能成为 传递给spawn_link的匿名函数可以调用它。

  3. MyModule.Heartbeat.start_link/0成功时需要返回{:ok, pid}spawn_link只返回一个pid。

  4. 这3次更改后的最终代码:

    defmodule MyModule.Heartbeat do
      def start_link do
        pid = spawn_link(fn ->
          :timer.apply_interval(:timer.seconds(5), __MODULE__, :beat, [])
          :timer.sleep(:infinity)
        end)
        {:ok, pid}
      end
    
      def beat do
        IO.puts "beat"
      end
    end
    
    defmodule MyModule.Supervisor do
      use Supervisor
    
      def start_link do
        Supervisor.start_link(__MODULE__, :ok)
      end
    
      def init(:ok) do
         children = [
           worker(MyModule.Heartbeat, [])
         ]
    
        supervise(children, strategy: :one_for_one)
      end
    end
    

    输出:

    iex(1)> MyModule.Supervisor.start_link
    {:ok, #PID<0.84.0>}
    iex(2)> beat
    beat
    beat
    beat
    

    我不确定你是否甚至需要所有这些设置作为该函数引发的异常 传递给:timer.apply_interval不会影响调用过程。该 以下脚本一直试图运行该函数,即使它总是引发一个 例外:

    defmodule Beat do
      def beat do
        raise "hey"
      end
    end
    
    :timer.apply_interval(:timer.seconds(1), Beat, :beat, [])
    :timer.sleep(:infinity)
    

    输出:

    $ elixir a.exs
    
    16:00:43.207 [error] Process #PID<0.53.0> raised an exception
    ** (RuntimeError) hey
        a.exs:3: Beat.beat/0
    
    16:00:44.193 [error] Process #PID<0.54.0> raised an exception
    ** (RuntimeError) hey
        a.exs:3: Beat.beat/0
    
    16:00:45.193 [error] Process #PID<0.55.0> raised an exception
    ** (RuntimeError) hey
        a.exs:3: Beat.beat/0
    
相关问题