I have a simple GenServer
within which I wish to create a loop that calls a function every two seconds:
defmodule MyModule do
use GenServer
def start_link(time) do
GenServer.start_link(__MODULE__,time)
end
#Start loop
def init(time) do
{:ok, myLoop(time)}
end
#Loop every two seconds
def myLoop(time) do
foo = bah(:someOtherProcess, {time})
IO.puts("The function value was: #{foo}")
:timer.sleep(2000)
myLoop(time + 2)
end
end
But when I call with:
{:ok, myServer} =MyModule.start_link(time)
IO.puts("Now I can carry on...")
I never see a return from the above call. This is kind of obvious I guess. So my question is, how can I create the loop I'd like without blocking the process from downstream execution tasks?
Thanks.
The best/cleanest way to accomplish what you are trying to do is with Process.send_after/3
. It delegates the timeout to the scheduler, not another process.
defmodule MyModule do
use GenServer
def start_link(time) do
GenServer.start_link(__MODULE__,time)
end
def init(time) do
schedule_do_something(time)
{:ok, %{time: time}}
end
def handle_info(:do_something, state) do
%{time: time} = state
# do something interesting here
schedule_do_something(time)
{:noreply, state}
end
defp schedule_do_something(time_in_seconds) do
Process.send_after(self, :do_something, (time_in_seconds * 1000))
end
end
A GenServer acts like an event loop anyway, so why reimplement this yourself?