<commit_before>require Logger

defmodule Serverboards.Plugin.Init do
  use GenServer

  defstruct [
    id: nil,
    name: nil,
    description: nil,
    command: nil,
    call: nil
  ]

  @max_timeout 60*60*2 # 2h

  def start_link(init, options \\ []) do
    GenServer.start_link(__MODULE__, init, options)
  end

  def from_component(c) do
    %Serverboards.Plugin.Init{
      id: c.id,
      name: c.name,
      description: c.description,
      command: c.extra["command"],
      call: c.extra["call"]
    }
  end


  ## impl
  def init(init) do
    state = %{
      running: false,
      init: init,
      task: nil,
      timeout: 1,
      timer: nil,
      started_at: nil
    }

    Logger.debug(inspect state)

    GenServer.cast(self(),{:start})

    {:ok, state}
  end

  def handle_cast({:start}, state) do
    Logger.info("Starting init service #{inspect state.init.id}", init: state.init)
    init = state.init
    task =  Task.async(Serverboards.Plugin.Runner, :start_call_stop, [init.command, init.call, []])
    #Process.monitor(task.pid)

    state = %{
      state |
      running: true,
      task: task,
      started_at: Timex.Duration.now()
    }

    Logger.debug("It should be running: #{inspect task}, #{inspect state}")

    {:noreply, state}
  end

  defp handle_wait_run(%{started_at: started_at, timeout: timeout } = state) do
    running_for_seconds = -Timex.Duration.diff(started_at, nil, :seconds)
    timeout = max(1, min((timeout - running_for_seconds) * 2, @max_timeout)) # 2h
    timer = Process.send_after(self(), {:restart}, timeout * 1000)
    state = %{
      state |
      timeout: timeout,
      timer: timer,
      started_at: nil,
      task: nil
    }
    Logger.info("Restart init #{state.init.id} in #{state.timeout} seconds.", state: state)
    state
  end

  def handle_info({:DOWN, _ref, :process, _pid, _type}, %{started_at: started_at} = state) when is_nil(started_at) do
    # this is when already finished properly, it may close the cmd.
    {:noreply, state}
  end
  def handle_info({:DOWN, ref, :process, pid, type}, state) do
    Logger.info("Init \"#{inspect state.init.id}\" down (#{inspect type}).")
    state = handle_wait_run(state)
    {:noreply, state}
  end
  def handle_info({:restart}, state) do
    handle_cast({:start}, state)
  end
  def handle_info({_ref, {:error, :unknown_method}}, state) do
    Logger.error("Cant run init, unknown method #{inspect state.init.call}")
    state = handle_wait_run(state)
    {:noreply, state}
  end
  def handle_info({_ref, {:error, :exit}}, state) do
    Logger.error("Error running ini, process exit #{inspect state.init.command}")
    state = handle_wait_run(state)
    {:noreply, state}
  end
  def handle_info({_ref, {:ok, waits}}, state) when is_number(waits) do
    %{started_at: started_at } = state
    running_for_seconds = -Timex.Duration.diff(started_at, nil, :seconds)
    timeout = max(1, waits)
    timer = Process.send_after(self(), {:restart}, timeout * 1000)
    state = %{
      state |
      timeout: timeout,
      timer: timer,
      started_at: nil,
      task: nil
    }<commit_msg>Show any error the same way, stating the error<commit_after>require Logger

defmodule Serverboards.Plugin.Init do
  use GenServer

  defstruct [
    id: nil,
    name: nil,
    description: nil,
    command: nil,
    call: nil
  ]

  @max_timeout 60*60*2 # 2h

  def start_link(init, options \\ []) do
    GenServer.start_link(__MODULE__, init, options)
  end

  def from_component(c) do
    %Serverboards.Plugin.Init{
      id: c.id,
      name: c.name,
      description: c.description,
      command: c.extra["command"],
      call: c.extra["call"]
    }
  end


  ## impl
  def init(init) do
    state = %{
      running: false,
      init: init,
      task: nil,
      timeout: 1,
      timer: nil,
      started_at: nil
    }

    Logger.debug(inspect state)

    GenServer.cast(self(),{:start})

    {:ok, state}
  end

  def handle_cast({:start}, state) do
    Logger.info("Starting init service #{inspect state.init.id}", init: state.init)
    init = state.init
    task =  Task.async(Serverboards.Plugin.Runner, :start_call_stop, [init.command, init.call, []])
    #Process.monitor(task.pid)

    state = %{
      state |
      running: true,
      task: task,
      started_at: Timex.Duration.now()
    }

    Logger.debug("It should be running: #{inspect task}, #{inspect state}")

    {:noreply, state}
  end

  defp handle_wait_run(%{started_at: started_at, timeout: timeout } = state) do
    running_for_seconds = -Timex.Duration.diff(started_at, nil, :seconds)
    timeout = max(1, min((timeout - running_for_seconds) * 2, @max_timeout)) # 2h
    timer = Process.send_after(self(), {:restart}, timeout * 1000)
    state = %{
      state |
      timeout: timeout,
      timer: timer,
      started_at: nil,
      task: nil
    }
    Logger.info("Restart init #{state.init.id} in #{state.timeout} seconds.", state: state)
    state
  end

  def handle_info({:DOWN, _ref, :process, _pid, _type}, %{started_at: started_at} = state) when is_nil(started_at) do
    # this is when already finished properly, it may close the cmd.
    {:noreply, state}
  end
  def handle_info({:DOWN, ref, :process, pid, type}, state) do
    Logger.info("Init \"#{inspect state.init.id}\" down (#{inspect type}).")
    state = handle_wait_run(state)
    {:noreply, state}
  end
  def handle_info({:restart}, state) do
    handle_cast({:start}, state)
  end
  def handle_info({_ref, {:error, :unknown_method}}, state) do
    Logger.error("Cant run init, unknown method #{inspect state.init.call}")
    state = handle_wait_run(state)
    {:noreply, state}
  end
  def handle_info({_ref, {:error, error}}, state) do
    Logger.error("Error running init #{inspect state.init.id}, error: #{inspect error}.", init: state.init, error: error)
    state = handle_wait_run(state)
    {:noreply, state}
  end
  def handle_info({_ref, {:ok, waits}}, state) when is_number(waits) do
    %{started_at: started_at } = state
    running_for_seconds = -Timex.Duration.diff(started_at, nil, :seconds)
    timeout = max(1, waits)
    timer = Process.send_after(self(), {:restart}, timeout * 1000)
    state = %{
      state |
      timeout: timeout,
      timer: timer,
      started_at: nil,
      task: nil
    }
{'fraction_non_alphanumeric': 0.1377559117600381, 'fraction_numerical': 0.006030788763688303, 'mean_word_length': 3.0397435897435896, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '936181', 'n_tokens_mistral': 2205, 'n_tokens_neox': 2091, 'n_words': 551}