lib/runbox/runtime/state_loader.ex

defmodule Runbox.Runtime.StateLoader do
  @moduledoc """
  Module handles run state load/initialization.
  """

  alias Runbox.Scenario.StartParams
  alias Runbox.Scenario.Type
  alias Runbox.StateStore

  require Logger

  @callback load_existing_state(StartParams.t(), instance_ctx :: map(), start_recipe :: []) ::
              {:ok, start_recipe :: []} | {:error, :no_savepoint}

  @callback init_new_state(StartParams.t(), instance_ctx :: map(), start_recipe :: []) ::
              {:ok, start_recipe :: []} | {:error, :no_savepoint}

  @doc """
  Fetches state into run start recipe.
  """
  @spec load(StartParams.t(), map(), start_recipe :: []) ::
          {:ok, start_recipe :: []} | {:error, :no_savepoint}
  def load(%StartParams{} = start_params, instance_context, start_recipe) do
    if StateStore.initialized?(instance_context.state_store_pid) do
      {time, res} =
        :timer.tc(fn ->
          get_impl(start_params.scenario_type).load_existing_state(
            start_params,
            instance_context,
            start_recipe
          )
        end)

      Logger.info("Run #{start_params.run_id} existing state loaded in #{div(time, 1000)}ms.")
      res
    else
      {time, res} =
        :timer.tc(fn ->
          get_impl(start_params.scenario_type).init_new_state(
            start_params,
            instance_context,
            start_recipe
          )
        end)

      Logger.info("Run #{start_params.run_id} new state loaded in #{div(time, 1000)}ms.")
      res
    end
  end

  @stage Type.stage()
  @simple Type.simple()
  defp get_impl(@stage), do: Runbox.Runtime.Stage.StateLoader
  defp get_impl(@simple), do: Runbox.Runtime.Simple.StateLoader
end