2016-07-22 43 views
1

我試圖產生一個進程,每五秒發送一個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> 

所有我需要的是一些過程,將運行的一部分監督樹並在指定的時間間隔內發送請求。它不需要能夠自己接收任何消息,我也不太爲特定的實現感到困擾。

任何人都可以提出我在這裏做錯了什麼,這阻止了這個過程開始,如果有可能有更好的方式來實現這一目標?

回答

2

有在你的代碼3個錯誤:立即

  1. :timer.apply_interval/4回報,因此匿名 功能MyModule.Heartbeat.start_link/0傳遞給spawn_link執行該行後不久終止 ,造成: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。

這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 
+0

爲什麼心跳繼續使用後,開始工作:無限的睡眠?整個事情不應該凍結和停止? –

+1

':timer.sleep(:infinity)'「凍結」只執行該代碼的進程(Erlang進程)。 ':timer'應用程序仍在運行,並以指定的時間間隔調用我們要求的函數。 – Dogbert

+0

太棒了,謝謝:) –