lib/rclex/job_executor.ex

defmodule Rclex.JobExecutor do
  require Logger
  use GenServer, restart: :transient

  @moduledoc """
  Receives job queue and executes queue element in order.

  * The execution order can be changed by using the change order function.
    * change order function receives list(), return list()

  Used by `Rclex.Timer` and `Rclex.Subscriber`.
  """

  @spec start_link({target_identifier :: charlist()}) :: GenServer.on_start()
  def start_link({target_identifier}) do
    GenServer.start_link(__MODULE__, {}, name: {:global, "#{target_identifier}/JobExecutor"})
  end

  @spec start_link({target_identifier :: charlist(), change_order :: (list() -> list())}) ::
          GenServer.on_start()
  def start_link({target_identifier, change_order}) do
    GenServer.start_link(__MODULE__, {change_order},
      name: {:global, "#{target_identifier}/JobExecutor"}
    )
  end

  @impl GenServer
  def init({}) do
    Logger.debug("JobExecutor start")
    {:ok, {}}
  end

  @impl GenServer
  def init({change_order}) do
    Logger.debug("JobExecutor start")
    {:ok, {change_order}}
  end

  @impl GenServer
  def handle_cast({:execute, job_queue}, {}) do
    for {key, action, args} <- :queue.to_list(job_queue) do
      GenServer.cast(key, {action, args})
    end

    {:noreply, {}}
  end

  @impl GenServer
  def handle_cast({:execute, job_queue}, {change_order}) do
    job_list = :queue.to_list(job_queue)

    for {key, action, args} <- change_order.(job_list) do
      GenServer.cast(key, {action, args})
    end

    {:noreply, {change_order}}
  end
end