lib/pistis/cluster/state_refresher.ex

defmodule Pistis.Cluster.StateRefresher do
  use GenServer
  use Pistis.Core.Journal
  alias Pistis.Cluster.Manager
  alias Pistis.Cluster.StateStorage
  alias Pistis.Pod.Raft

  @me __MODULE__
  @heartbeat 2000

  def boot(), do: Pistis.Core.Supervisor.supervise(@me)

  def start_link(_args \\ []), do: GenServer.start_link(@me, %{}, name: @me)

  def init(state) do
    schedule_work(@heartbeat * 5)
    {:ok, state}
  end

  def handle_info(:work, state) do
    refresh_cluster_state()
    schedule_work(@heartbeat)
    {:noreply, state}
  end

  defp refresh_cluster_state() do
    {_, node_address} = Manager.leader_node()
    {:ok, refreshed_members, leader} = Raft.cluster_members(node_address)

    current_state = StateStorage.read()
    catalogued_failures = current_state.failures
    solved_failures = Enum.filter(catalogued_failures, fn f_node -> f_node in refreshed_members end)
    unsolved_failures = Enum.filter(catalogued_failures, fn f_node -> f_node not in refreshed_members end)

    new_members = Map.get(StateStorage.read(), :members) ++ solved_failures

    StateStorage.store(members: new_members)
    StateStorage.store(failures: unsolved_failures)

    unless current_state.leader == leader do
      StateStorage.store(leader: leader)
    end
  end

  defp schedule_work(delay) do
    Process.send_after(self(), :work, delay)
  end
end