Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create an event emitter with elixir, the otp way

What is the best way in elixir to create a foreground process that tick on every given amount of time?

My main problem is that an approach like:

defmoulde Ticker do
  def tick do
    do_something()
    :timer.sleep(1000)
    tick
  end
end

works, but is wrong by design. It's definitely not ticking every second, but every second PLUS the time for do_something() to complete. I could spawn a process to handle the "something" but still there is a small lag.

Also, I'm trying to build a mix app, there is some GenServers involved, and a main foreground process (the one I'm asking here) that should call the servers every x seconds. Is there an otp way of doing this?

like image 883
matteosister Avatar asked Jul 14 '15 14:07

matteosister


2 Answers

If you prefer sending a message instead of calling a function at a given interval, you can use :timer.send_interval/3

E.g. if you want to send a message to a GenServer every second as OP mentions in their answer, you could do the following:

:timer.send_interval(:timer.seconds(1), target_pid, :tick)

Where target_pid is the PID of the GenServer you want to send a message to. Then you can handle this message in your GenServer like this:

def handle_info(:tick, state) do
  do_something()
  {:noreply, state}
end
like image 88
Zoltán Avatar answered Sep 28 '22 08:09

Zoltán


I think timer:apply_interval/4 should suit your needs. It is used something like this:

defmodule Tick do
  def tick do
    IO.inspect(:tick)
  end
end

:timer.apply_interval(:timer.seconds(1), Tick, :tick, [])

The arguments in order are the interval, a module name, the function to call and the arguments to call it with. Then you can send messages to your GenServers inside that function. Check out the full documentation here: apply_interval/4

Another thing to consider is that if your tick function is only ever sending simple messages to some GenServers then it is probably extremely fast, so your implementation might be OK, once wrapped in a Task and plugged into the supervision tree (if you don't care about the potential slight drift that is).

like image 27
Paweł Obrok Avatar answered Sep 28 '22 07:09

Paweł Obrok