Tickers in Elixir

Tickers are for when you want to do something repeatedly at regular intervals. Here’s an example of a ticker that ticks periodically until we stop it.

defmodule Tickers do
  def run do
    # Tickers use a similar mechanism to timers: a process that sends messages
    # Here we'll use a receive block to await the messages as they arrive every 500ms.
    ticker_pid = spawn_link(fn -> ticker(self()) end)
    
    receive_loop(ticker_pid)
  end

  defp ticker(parent_pid) do
    send(parent_pid, {:tick, DateTime.utc_now()})
    Process.sleep(500)
    ticker(parent_pid)
  end

  defp receive_loop(ticker_pid) do
    receive do
      {:tick, time} ->
        IO.puts("Tick at #{time}")
        receive_loop(ticker_pid)
    after
      1600 ->
        Process.exit(ticker_pid, :normal)
        IO.puts("Ticker stopped")
    end
  end
end

Tickers.run()

In this Elixir version, we use a separate process to simulate the ticker. The ticker/1 function sends a message to the parent process every 500 milliseconds. The receive_loop/1 function receives these messages and prints them.

Tickers can be stopped like timers. Once a ticker is stopped, it won’t send any more messages. We’ll stop ours after 1600ms by terminating the ticker process.

When we run this program, the ticker should tick 3 times before we stop it.

$ elixir tickers.exs
Tick at 2023-06-01 12:34:56.789Z
Tick at 2023-06-01 12:34:57.290Z
Tick at 2023-06-01 12:34:57.791Z
Ticker stopped

In Elixir, we use processes and message passing to achieve concurrent behavior, which is similar to Go’s goroutines and channels. The spawn_link/1 function creates a new process, and we use send/2 and receive for inter-process communication.

The Process.sleep/1 function is used to introduce delays, similar to time.Sleep in Go. To stop the ticker, we use Process.exit/2 to terminate the ticker process.

This example demonstrates how to create periodic tasks in Elixir and how to use processes for concurrent programming.