Timers in Elixir

Our first example will demonstrate how to use timers in Elixir. We’ll explore how to execute code at some point in the future or repeatedly at some interval.

defmodule Timers do
  def run do
    # Timers represent a single event in the future. You
    # tell the timer how long you want to wait, and it
    # will send a message when that time has elapsed.
    # This timer will wait 2 seconds.
    timer1 = Process.send_after(self(), :timer1, 2000)

    # We'll receive the message sent by the timer
    receive do
      :timer1 -> IO.puts("Timer 1 fired")
    end

    # If you just wanted to wait, you could have used
    # Process.sleep/1. One reason a timer may be useful is
    # that you can cancel the timer before it fires.
    # Here's an example of that.
    timer2 = Process.send_after(self(), :timer2, 1000)

    # Start a separate process to handle the timer2 message
    spawn(fn ->
      receive do
        :timer2 -> IO.puts("Timer 2 fired")
      end
    end)

    # Cancel timer2
    result = Process.cancel_timer(timer2)
    if result != false do
      IO.puts("Timer 2 stopped")
    end

    # Give timer2 enough time to fire, if it ever
    # was going to, to show it is in fact stopped.
    Process.sleep(2000)
  end
end

Timers.run()

The first timer will fire ~2 seconds after we start the program, but the second should be stopped before it has a chance to fire.

$ elixir timers.exs
Timer 1 fired
Timer 2 stopped

In this Elixir version:

  1. We use Process.send_after/3 to create timers that send messages after a specified delay.
  2. We use receive to wait for and handle timer messages.
  3. We use Process.cancel_timer/1 to stop a timer before it fires.
  4. We use spawn/1 to create a separate process for handling the second timer, simulating concurrent behavior.

Elixir’s approach to timers is more message-based compared to Go’s channel-based approach, but the core concepts remain similar. This example demonstrates how to create, use, and cancel timers in Elixir.