farmbot_os/farmbot_core/lib/farmbot_core/firmware_estop_timer.ex

59 lines
1.7 KiB
Elixir

defmodule FarmbotCore.FirmwareEstopTimer do
@moduledoc """
Process that wraps a `Process.send_after/3` call.
When `:timeout` is received, a `fatal_email` log message will be
dispatched.
"""
use GenServer
require FarmbotCore.Logger
@msg "Farmbot has been E-Stopped for more than 10 minutes."
@ten_minutes_ms 60_0000
def start_timer(timer_server \\ __MODULE__) do
GenServer.call(timer_server, :start_timer)
end
def cancel_timer(timer_server \\ __MODULE__) do
GenServer.call(timer_server, :cancel_timer)
end
@doc """
optional args:
* `timeout_ms` - amount of milliseconds to run timer for
* `timeout_function` - function to call instead of logging
opts - GenServer.options()
"""
@spec start_link(Keyword.t(), GenServer.options()) :: GenServer.on_start()
def start_link(args, opts \\ [name: __MODULE__]) do
GenServer.start_link(__MODULE__, args, opts)
end
def init(args) do
timeout_ms = Keyword.get(args, :timeout_ms, @ten_minutes_ms)
timeout_fun = Keyword.get(args, :timeout_function, &do_log/0)
state = %{timer: nil, timeout_ms: timeout_ms, timeout_function: timeout_fun}
{:ok, state, :hibernate}
end
def handle_call(:start_timer, _from, state) do
timer = Process.send_after(self(), :timeout, state.timeout_ms)
{:reply, timer, %{state | timer: timer}}
end
def handle_call(:cancel_timer, _from, state) do
state.timer && Process.cancel_timer(state.timer)
{:reply, state.timer, %{state | timer: nil}, :hibernate}
end
def handle_info(:timeout, state) do
_ = apply(state.timeout_function, [])
{:noreply, %{state | timer: nil}, :hibernate}
end
@doc false
def do_log, do: FarmbotCore.Logger.warn(1, @msg, channels: [:fatal_email])
end