Presence updated every second from GenServer: best practice?

Hello,

I have a GenServer module that takes care of sending the time left for the start of the upcoming games via Phoenix Presence. My code works, but given that I started coding in Elixir a couple of days ago I’d like to know whether there is something that I could do better (I’m used to Node.js and everything is very different). Thanks in advance for any advice!

defmodule Hydnix.GameScheduler do
    require Logger
    use GenServer, restart: :transient
    use Timex
    alias Hydnix.Core
    alias HydnixWeb.Presence
    alias Timex.Duration
  
    def start_link(args) do
        GenServer.start_link(__MODULE__, args)
    end

    def init(args) do
        pid = Keyword.get(args, :pid)

        Core.next_games()
        |> Enum.with_index()
        |> Enum.each(fn {e, _idx} ->
            {:ok, _} = Presence.track(Keyword.get(args, :pid), "game:#{e.id}", "time_left_to_start", %{
                value: time_left_to_start(e.starts_at),
                pid: self()
            })

            :timer.apply_interval(:timer.seconds(1), Hydnix.GameScheduler, :update, [{pid, e}])
        end)

        {:ok, args}
    end

    def update(args) do
        {pid, e} = args

        {:ok, _} = Presence.update(pid, "game:#{e.id}", "time_left_to_start", %{
            value: time_left_to_start(e.starts_at),
            pid: self()
        })
    end

    def time_left_to_start(starts_at) do
        Timex.diff(starts_at, DateTime.utc_now, :seconds)
        |> Duration.from_seconds
        |> Duration.to_string
    end
end
1 Like

Your init function is likely doing too much. Have a look at GenServer.handle_continue.

1 Like

If this is restart: transient, if it ever crashes you will lose notifications, on your system, forever, until you restart.

Is there some reason why you aren’t doing this inside each game’s genserver?

I’m also not sure why this is a genserver. Genservers should represent discrete failure domains, in this case it looks like you’re aggregating multiple failure domains (multiple games) and giving them a single point of failure.